kopia/kopia · error
placeholderPath dir creation
Error message
placeholderPath dir creation
What it means
When building a shallow placeholder path for a snapshot.EntryTypeDirectory, placeholderPath must os.MkdirAll the '<path>.kopia-entry' directory (using SafeLongFilename). If that mkdir fails (permissions, disk full, path too long), the error is wrapped as "placeholderPath dir creation".
Solutions
- Check the destination parent is writable by the process user and not mounted read-only
- Delete any stale regular file occupying the '<path>.kopia-entry' name
- Inspect errors.Cause(err) for EACCES/ENOSPC/ENAMETOOLONG and address it (free space, enable long paths)
- Re-run the operation; MkdirAll is idempotent once the obstacle is removed
Example fix
// before
mp, err := localfs.WriteShallowPlaceholder(destPath, de) // fails: dest on read-only fs
// after
if test -w parent; then ... fi — in Go:
if err := os.MkdirAll(filepath.Dir(destPath), 0o755); err != nil {
return fmt.Errorf("destination %q not writable: %w", destPath, err)
}
mp, err := localfs.WriteShallowPlaceholder(destPath, de) Defensive patterns
Strategy: validation
Validate before calling
parent := filepath.Dir(path)
if err := unix.Access(parent, unix.W_OK); err != nil {
return fmt.Errorf("destination %q not writable: %w", parent, err)
}
if fi, err := os.Lstat(path + ".kopia-entry"); err == nil && !fi.IsDir() {
return fmt.Errorf("%q exists and is not a directory", path+".kopia-entry")
} Try / catch
mp, err := localfs.WriteShallowPlaceholder(path, de)
if err != nil {
if os.IsPermission(errors.Cause(err)) {
return fmt.Errorf("cannot create placeholder dir for %q: permission denied", path)
}
return fmt.Errorf("placeholder %q: %w", path, err)
} Prevention
- Verify destination writability before bulk placeholder writes
- Clear stale '<path>.kopia-entry' files from failed runs
- Enable long-path support on Windows for deep trees
- Check free disk space before large shallow-copy operations
When it happens
Trigger: Calling WriteShallowPlaceholder (via writeShallowEntry) for a directory entry whose placeholder directory cannot be created: read-only filesystem, missing write permission on the parent, ENAMETOOLONG/ENOSPC, or the target path exists as a plain file blocking MkdirAll.
Common situations: Restoring/duplicating shallow placeholders onto a read-only volume or a Windows ACL-protected folder; long paths in deep trees on Windows without long-path support; an existing regular file named '<dir>.kopia-entry' left by a prior failed run.
Understand the failure class
Background: mkdir permission denied (EACCES): failed to create directory errors explained — this error's family across 32 libraries.
Related errors
- error writing placeholder to
- unsupported entry type
- can't re-create top-level directory
- cannot create directory
- cannot create parent directory for temp file
AI-assisted analysis of kopia/kopia@82495e54b5 (2026-09-07).
Data as JSON: /api/errors/0669ac109507accf.
Report an issue: GitHub.
Appendix: source
Thrown at fs/localfs/shallow_fs.go:31
"github.com/kopia/kopia/internal/atomicfile"
"github.com/kopia/kopia/internal/ospath"
"github.com/kopia/kopia/snapshot"
)
// Helpers to implement storing of "shallow" placeholders for files or
// directory trees in a restore image. A placeholder for directory d1 is
// d1.kopia-entry/.kopia-entry. As a result, d1.kopia-entry will stat as
// a directory and show up nicely in colorized ls output. A placeholder
// for a file f1 is f1.kopia-entry.
func placeholderPath(path string, et snapshot.EntryType) (string, error) {
switch et {
case snapshot.EntryTypeFile:
return path + ShallowEntrySuffix, nil
case snapshot.EntryTypeDirectory: // Directories and regular files
dirpath := path + ShallowEntrySuffix
if err := os.MkdirAll(ospath.SafeLongFilename(dirpath), os.FileMode(dirMode)); err != nil {
return "", errors.Wrap(err, "placeholderPath dir creation")
}
return filepath.Join(dirpath, ShallowEntrySuffix), nil
default:
// Shouldn't be used on links or other file types.
return "", errors.Errorf("unsupported entry type: %v", et)
}
}
// WriteShallowPlaceholder writes sufficient metadata into the placeholder
// file associated with path so that it can be roundtripped through
// snapshot/restore without needing to be realized in the local
// filesystem.
// TODO(rjk): Should the placeholder use the complete fs.Entry?
func WriteShallowPlaceholder(path string, de *snapshot.DirEntry) (string, error) {
buffy := &bytes.Buffer{}
encoder := json.NewEncoder(buffy)
View on GitHub (pinned to 82495e54b5)