Issue Description
Building an image FROM a base image that has layers but an empty/absent history (e.g. produced with buildah build --omit-history or buildah commit --squash --omit-history) currently produces inconsistent and always suboptimal results, depending on the tool and version:
- Buildah 1.42.x: the build succeeds, but the child image silently ends up with no history at all (
forceOmitHistory).
- Podman 4.9.5: the build aborts with an internal consistency error as soon as the child records a history entry of its own.
- Docker 24.0 accepts the base and appends the child's history entries without synthesizing records for the inherited layers, so layer-aware tools such as
dive associate the child's history with the wrong filesystem layers.
I know that the history is optional according to the OCI image spec. But omitting a history when --omit-history is not passed is unexpected.
Steps to reproduce the issue
-
Create a base image that has a layer but no history:
$ echo hello > test.txt
$ printf 'FROM scratch\nCOPY test.txt /test.txt\n' > Containerfile.base
$ buildah build --omit-history -t localhost/base:nohistory -f Containerfile.base .
$ skopeo inspect --config containers-storage:localhost/base:nohistory | jq '{layers: (.rootfs.diff_ids|length), history: .history}'
# 1 layer, empty/absent history
-
Build a child that records a metadata step before adding a layer:
$ printf 'FROM localhost/base:nohistory\nARG SOURCE_DATE_EPOCH=315532800\nCOPY test.txt /test2.txt\n' > Containerfile.child
$ buildah build -t localhost/child -f Containerfile.child .
$ # resp. podman and docker build
Describe the results you received
Podman 4.9.5: hard failure:
STEP 2/3: ARG SOURCE_DATE_EPOCH=315532800
--> c577ce811744
STEP 3/3: COPY test.txt /test2.txt
Error: committing container for step {... Command:copy Args:[test.txt /test2.txt] ...}:
copying layers and metadata for container "...": initializing source
containers-storage:c577ce811744-working-container: internal error:
history lists 1 non-empty layers, but we have 2 layers on disk
Buildah 1.42.x: the build succeeds, but the child has no history:
$ skopeo inspect --config containers-storage:localhost/child | jq '.history'
null
Docker 24.0: the build succeeds, but the child's history entries are appended without placeholder records for the inherited base layer(s), so dive (and similar layer-aware tools) attribute the child's history to the wrong layers.
Describe the results you expected
A consistent, documented, and structurally correct behavior, ideally:
- The build succeeds and synthesizes blank placeholder history entries for the base image's filesystem layers, so the child's history stays consistent and effectively "starts with its own layers" (preferred), or failing that,
- A clear, actionable error at the
FROM step stating that the base image has layers but no history, so the user explicitly needs to add --omit-history.
Not silent history loss (Buildah), an internal error (Podman 4.9.5), or silently misaligned history (Docker).
Root cause (from image.go)
makeContainerImageRef sets forceOmitHistory = true when the parent's history is completely empty (len(b.OCIv1.History) == 0 && len(b.OCIv1.RootFS.DiffIDs) != 0). The code comment says this avoids "an image with multiple layers, only some of which have history entries."
Possible solutions
Ranked:
- Synthesize blank placeholder history entries for the base image's filesystem layers (
empty_layer absent/false, blank fields), so the child's history stays consistent and consumers can append correctly. Buildah already appends structured entries via preEmptyLayers/postEmptyLayers. This avoids both the Docker problem (misaligned history) and the Buildah problem (dropped history).
- Fail fast at
FROM with a clear, actionable error, so the user explicitly needs to add --omit-history, if Buildah deliberately refuses to repair third-party images.
- Force-omit history (current Buildah behavior): last resort, ideally explicit/opt-in, since it silently discards history for all descendants.
- Append without padding (Docker's behavior): avoids the failed build but demonstrably misleads layer-aware tools; avoid.
buildah version output
Version: 1.43.1
Go Version: go1.26.1-X:nodwarf5
Image Spec: 1.1.1
Runtime Spec: 1.2.1
CNI Spec: 1.1.0
libcni Version:
image Version: 5.39.2
Git Commit:
Built: Wed Apr 8 19:37:51 2026
OS/Arch: linux/arm64
BuildPlatform: linux/arm64/v8
buildah info output
{
"host": {
"CgroupVersion": "v2",
"Distribution": {
"distribution": "fedora",
"version": "44"
},
"MemFree": 181133312,
"MemTotal": 2036867072,
"OCIRuntime": "crun",
"SwapFree": 0,
"SwapTotal": 0,
"arch": "arm64",
"cpus": 6,
"hostname": "d1b12df9c461",
"kernel": "6.17.7-300.fc43.aarch64",
"os": "linux",
"rootless": true,
"uptime": "10h 18m 57.17s (Approximately 0.42 days)",
"variant": ""
},
"store": {
"ContainerStore": {
"number": 0
},
"GraphDriverName": "overlay",
"GraphImageStore": "",
"GraphOptions": [
"overlay.imagestore=/var/lib/shared",
"overlay.imagestore=/usr/lib/containers/storage",
"overlay.mount_program=/usr/bin/fuse-overlayfs",
"overlay.mountopt=nodev,fsync=0"
],
"GraphRoot": "/var/lib/containers/storage",
"GraphStatus": {
"Backing Filesystem": "xfs",
"Native Overlay Diff": "false",
"Supports d_type": "true",
"Supports shifting": "true",
"Supports volatile": "true",
"Using metacopy": "false"
},
"GraphTransientStore": false,
"ImageStore": {
"number": 0
},
"RunRoot": "/run/containers/storage"
}
}
Provide your storage.conf
[storage]
driver = "overlay"
runroot = "/run/containers/storage"
graphroot = "/var/lib/containers/storage"
[storage.options]
additionalimagestores = [
"/usr/lib/containers/storage",
]
pull_options = {enable_partial_images = "true", use_hard_links = "false", ostree_repos=""}
[storage.options.overlay]
mountopt = "nodev,metacopy=on"
Upstream Latest Release
No
Additional environment details
Tested in a GitLab Pipeline with Docker Runners on Linux and using podman on macOS (via podman machine).
Additional information
- Arose in a reproducible-builds pipeline (
--source-date-epoch + --rewrite-timestamp + caching), where --omit-history is currently the only way to avoid non-static history content.
Issue Description
Building an image
FROMa base image that has layers but an empty/absenthistory(e.g. produced withbuildah build --omit-historyorbuildah commit --squash --omit-history) currently produces inconsistent and always suboptimal results, depending on the tool and version:forceOmitHistory).diveassociate the child's history with the wrong filesystem layers.I know that the
historyis optional according to the OCI image spec. But omitting a history when--omit-historyis not passed is unexpected.Steps to reproduce the issue
Create a base image that has a layer but no history:
Build a child that records a metadata step before adding a layer:
Describe the results you received
Podman 4.9.5: hard failure:
Buildah 1.42.x: the build succeeds, but the child has no history:
Docker 24.0: the build succeeds, but the child's history entries are appended without placeholder records for the inherited base layer(s), so
dive(and similar layer-aware tools) attribute the child's history to the wrong layers.Describe the results you expected
A consistent, documented, and structurally correct behavior, ideally:
FROMstep stating that the base image has layers but no history, so the user explicitly needs to add--omit-history.Not silent history loss (Buildah), an internal error (Podman 4.9.5), or silently misaligned history (Docker).
Root cause (from
image.go)makeContainerImageRefsetsforceOmitHistory = truewhen the parent's history is completely empty (len(b.OCIv1.History) == 0 && len(b.OCIv1.RootFS.DiffIDs) != 0). The code comment says this avoids "an image with multiple layers, only some of which have history entries."Possible solutions
Ranked:
empty_layerabsent/false, blank fields), so the child's history stays consistent and consumers can append correctly. Buildah already appends structured entries viapreEmptyLayers/postEmptyLayers. This avoids both the Docker problem (misaligned history) and the Buildah problem (dropped history).FROMwith a clear, actionable error, so the user explicitly needs to add--omit-history, if Buildah deliberately refuses to repair third-party images.buildah version output
buildah info output
Provide your storage.conf
Upstream Latest Release
No
Additional environment details
Tested in a GitLab Pipeline with Docker Runners on Linux and using podman on macOS (via podman machine).
Additional information
--source-date-epoch+--rewrite-timestamp+ caching), where--omit-historyis currently the only way to avoid non-static history content.