dagger/dagger · error

failed to lstat %s: %w

Error message

failed to lstat %s: %w

What it means

nixosLike.Install calls ctrFS.Lstat on the CA bundle path to determine whether it's a symlink, a missing file, or something else. ErrNotExist means the bundle doesn't exist yet (commonInstaller will create it) and a symlink triggers the swap logic; any other Lstat error aborts installation with this wrapped error.

Source

Thrown at engine/engineutil/cacerts/distros.go:261

		targetPath := target
		if !filepath.IsAbs(targetPath) {
			targetPath = filepath.Join(filepath.Dir(d.bundlePath), targetPath)
		}
		content, err := d.ctrFS.ReadFile(targetPath)
		if err != nil {
			return fmt.Errorf("failed to read symlink target %s for %s: %w", targetPath, d.bundlePath, err)
		}
		if err := d.ctrFS.Remove(d.bundlePath); err != nil {
			return fmt.Errorf("failed to remove symlink %s: %w", d.bundlePath, err)
		}
		if err := d.ctrFS.WriteFile(d.bundlePath, content, 0o644); err != nil {
			return fmt.Errorf("failed to materialize %s: %w", d.bundlePath, err)
		}
		d.origSymlinkTarget = target
	case errors.Is(err, os.ErrNotExist):
		// No bundle yet — commonInstaller will create one.
	case err != nil:
		return fmt.Errorf("failed to lstat %s: %w", d.bundlePath, err)
	}
	return d.commonInstaller.Install(ctx)
}

func (d *nixosLike) Uninstall(ctx context.Context) error {
	// Run commonInstaller's uninstall regardless of whether we swapped the
	// symlink. Capture its error and keep going — the symlink restore below
	// is the only thing that frees up the materialized bundle (which may still
	// contain the cert if commonInstaller.Uninstall failed).
	rerr := d.commonInstaller.Uninstall(ctx)
	if d.origSymlinkTarget == "" {
		return rerr
	}
	target := d.origSymlinkTarget
	d.origSymlinkTarget = ""
	if err := d.ctrFS.Remove(d.bundlePath); err != nil && !errors.Is(err, os.ErrNotExist) {
		rerr = errors.Join(rerr, fmt.Errorf("failed to remove materialized bundle %s: %w", d.bundlePath, err))
	}

View on GitHub (pinned to 82ba2681db)

Solutions

  1. Check the wrapped cause: if ENOTDIR/ENOENT on the parent, create the directory or fix SSL_CERT_FILE to a valid absolute path
  2. Ensure /etc/ssl/certs exists and is traversable in the image
  3. Fix permissions so the engine process can stat the path
  4. If SSL_CERT_FILE points somewhere invalid, unset it so the default bundle path is used
Defensive patterns

Strategy: validation

Validate before calling

if fi, err := os.Stat("/etc/ssl/certs"); err != nil || !fi.IsDir() {
    return fmt.Errorf("/etc/ssl/certs must be a traversable directory in the image")
}
if v, ok := os.LookupEnv("SSL_CERT_FILE"); ok && !filepath.IsAbs(v) {
    return fmt.Errorf("SSL_CERT_FILE must be an absolute path, got %q", v)
}

Prevention

When it happens

Trigger: ctrFS.Lstat(d.bundlePath) returns an unexpected error (EACCES, EIO, ENOTDIR, etc.) during nixosLike.Install — e.g. /etc/ssl/certs doesn't exist as a directory or is unreadable.

Common situations: Minimal Nix/distroless images missing /etc/ssl/certs as a traversable directory; permission-restricted rootless containers; I/O errors on damaged snapshots.

Related errors


AI-assisted analysis of dagger/dagger@82ba2681db (2026-09-05). Data as JSON: /api/errors/d914fdae71ca6034. Report an issue: GitHub.