dagger/dagger · error
cannot determine upperdir from mount option
Error message
cannot determine upperdir from mount option
What it means
After selecting the mount configuration, GetUpperdir extracts the final layer of the upper overlay stack as the upperdir. This error fires when that value ends up empty — i.e. the upper overlay mount parsed successfully but yielded no layers or no upperdir= option, so the code cannot name the directory holding the writable changes.
Source
Thrown at engine/snapshots/fsdiff/overlay_linux.go:69
upperlayers, err := GetOverlayLayers(upperM)
if err != nil {
return "", err
}
if len(upperlayers) != len(lowerlayers)+1 {
return "", errors.Errorf("cannot determine diff of more than one upper directories")
}
for i := 0; i < len(lowerlayers); i++ {
if upperlayers[i] != lowerlayers[i] {
return "", errors.Errorf("layer %d must be common between upper and lower snapshots", i)
}
}
upperdir = upperlayers[len(upperlayers)-1]
} else {
return "", errors.Errorf("multiple mount configurations are not supported")
}
if upperdir == "" {
return "", errors.Errorf("cannot determine upperdir from mount option")
}
return upperdir, nil
}
func GetOverlayLayers(m mount.Mount) ([]string, error) {
var u string
var uFound bool
var l []string
for _, o := range m.Options {
if strings.HasPrefix(o, "upperdir=") {
u, uFound = strings.TrimPrefix(o, "upperdir="), true
} else if strings.HasPrefix(o, "lowerdir=") {
l = strings.Split(strings.TrimPrefix(o, "lowerdir="), ":")
for i, j := 0, len(l)-1; i < j; i, j = i+1, j-1 {
l[i], l[j] = l[j], l[i]
}
} else if strings.HasPrefix(o, "workdir=") || o == "index=off" || o == "userxattr" || strings.HasPrefix(o, "redirect_dir=") || o == "volatile" {
continueView on GitHub (pinned to 82ba2681db)
Solutions
- Ensure the upper mount is a writable overlay mount whose Options include an upperdir= entry
- Verify you are passing the upper snapshot's mount (with upperdir), not a lower/read-only view, as the upper argument
- Inspect m.Options of the upper mount before calling and confirm upperdir=/lowerdir= are present
- Fix or update the snapshotter/mount helper that is dropping the upperdir option
Example fix
// before
upperM := mount.Mount{Type: "overlay", Source: "overlay", Options: []string{"lowerdir=/a:/b"}} // read-only
// after
upperM := mount.Mount{Type: "overlay", Source: "overlay", Options: []string{"lowerdir=/a:/b", "upperdir=/c", "workdir=/w"}} Defensive patterns
Strategy: validation
Validate before calling
func hasUpperdir(m mount.Mount) bool {
for _, o := range m.Options {
if strings.HasPrefix(o, "upperdir=") && len(o) > len("upperdir=") {
return true
}
}
return false
}
// call before diffing:
if !hasUpperdir(upperM) { return fmt.Errorf("upper mount has no upperdir; it is read-only or malformed") } Type guard
func isWritableOverlayMount(m mount.Mount) bool {
if m.Type != "overlay" { return false }
for _, o := range m.Options {
if strings.HasPrefix(o, "upperdir=") { return true }
}
return false
} Prevention
- Confirm the upper snapshot is mounted writable before diffing
- Don't pass read-only overlay views as the upper mount
- Validate mount options with a hasUpperdir check first
When it happens
Trigger: The upper mount's Options contain no upperdir= entry and its lowerdir list is empty (GetOverlayLayers returns nil), making upperlayers[len-1] unreachable/empty — e.g. a read-only overlay mount with only lowerdir, an options list with only ignorable options (workdir=/index=off/...), or a malformed mount produced by the snapshotter.
Common situations: Diffing a read-only overlay view (no upperdir by design); a snapshotter that mounts overlay without an upperdir option; an options list that lost its upperdir due to a mount-helper or logging wrapper rewriting options; passing a lower-style overlay mount as the upper mount by mistake.
Related errors
- could not find upperdir in mount options %v
- could not find lowerdir in mount options %v
- failed to stat underlying file from bind mount
- cannot determine diff of more than one upper directories
- layer %d must be common between upper and lower snapshots
AI-assisted analysis of dagger/dagger@82ba2681db (2026-09-05).
Data as JSON: /api/errors/4e165ac6c3804d34.
Report an issue: GitHub.