dagger/dagger · error

invalid remove path %q: absolute paths are not allowed

Error message

invalid remove path %q: absolute paths are not allowed

What it means

safeLocalExportRemovePath rejects remove paths that are absolute (or carry a Windows volume name) during local export diff sync. This is a path-traversal guard: deletes are only allowed for paths relative to the export root. The remote sync diff sent an absolute path, which the client refuses.

Source

Thrown at engine/client/filesync.go:345

	}

	for {
		msg := filesync.BytesMessage{}
		if err := stream.RecvMsg(&msg); err != nil {
			if errors.Is(err, io.EOF) {
				return nil
			}
			return err
		}
		if _, err := destF.Write(msg.Data); err != nil {
			return err
		}
	}
}

func safeLocalExportRemovePath(absRoot, removePath string) (string, error) {
	if filepath.IsAbs(removePath) || filepath.VolumeName(removePath) != "" {
		return "", fmt.Errorf("invalid remove path %q: absolute paths are not allowed", removePath)
	}
	if strings.Contains(removePath, `\`) {
		return "", fmt.Errorf("invalid remove path %q: backslashes are not allowed in diff paths", removePath)
	}

	cleanRel := path.Clean(strings.TrimSuffix(removePath, "/"))
	if cleanRel == "." || cleanRel == ".." || strings.HasPrefix(cleanRel, "../") {
		return "", fmt.Errorf("invalid remove path %q: escapes export root", removePath)
	}

	target := filepath.Join(absRoot, filepath.FromSlash(cleanRel))
	rel, err := filepath.Rel(absRoot, target)
	if err != nil {
		return "", fmt.Errorf("validate remove path %q: %w", removePath, err)
	}
	if rel == "." || rel == ".." || strings.HasPrefix(rel, ".."+string(filepath.Separator)) || filepath.IsAbs(rel) {
		return "", fmt.Errorf("invalid remove path %q: escapes export root", removePath)
	}

View on GitHub (pinned to 82ba2681db)

Solutions

  1. Ensure the sync engine emits delete paths relative to the session root.
  2. Strip the leading root prefix from paths before issuing remove operations.
  3. Update the client/engine pair to matching versions so diff-path conventions agree.

Example fix

// before
removePath := "/home/dev/project/file.txt"
// after: make it relative to the export root
removePath = strings.TrimPrefix(removePath, root+"/")
Defensive patterns

Strategy: validation

Validate before calling

func isSafeRemovePath(p string) bool {
    return !filepath.IsAbs(p) && filepath.VolumeName(p) == ""
}

Try / catch

if _, err := safeLocalExportRemovePath(root, p); err != nil {
    log.Printf("skipping unsafe remove %q: %v", p, err)
    return nil // or convert to a relative path and retry
}

Prevention

When it happens

Trigger: A filesync remove/delete operation carries a removePath like "/etc/passwd" or "C:\\tmp\\f" (VolumeName non-empty) into safeLocalExportRemovePath via DiffCopy.

Common situations: A buggy or malicious remote engine sends absolute delete paths; a sync root configured with absolute-style diff paths; cross-OS sync where Windows drive letters leak into paths.

Related errors


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