{"record":{"id":"0669ac109507accf","repo":"kopia/kopia","slug":"placeholderpath-dir-creation","errorCode":null,"errorMessage":"placeholderPath dir creation","messagePattern":"placeholderPath dir creation","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"fs/localfs/shallow_fs.go","lineNumber":31,"sourceCode":"\t\"github.com/kopia/kopia/internal/atomicfile\"\n\t\"github.com/kopia/kopia/internal/ospath\"\n\t\"github.com/kopia/kopia/snapshot\"\n)\n\n// Helpers to implement storing of \"shallow\" placeholders for files or\n// directory trees in a restore image. A placeholder for directory d1 is\n// d1.kopia-entry/.kopia-entry. As a result, d1.kopia-entry will stat as\n// a directory and show up nicely in colorized ls output. A placeholder\n// for a file f1 is f1.kopia-entry.\n\nfunc placeholderPath(path string, et snapshot.EntryType) (string, error) {\n\tswitch et {\n\tcase snapshot.EntryTypeFile:\n\t\treturn path + ShallowEntrySuffix, nil\n\tcase snapshot.EntryTypeDirectory: // Directories and regular files\n\t\tdirpath := path + ShallowEntrySuffix\n\t\tif err := os.MkdirAll(ospath.SafeLongFilename(dirpath), os.FileMode(dirMode)); err != nil {\n\t\t\treturn \"\", errors.Wrap(err, \"placeholderPath dir creation\")\n\t\t}\n\n\t\treturn filepath.Join(dirpath, ShallowEntrySuffix), nil\n\tdefault:\n\t\t// Shouldn't be used on links or other file types.\n\t\treturn \"\", errors.Errorf(\"unsupported entry type: %v\", et)\n\t}\n}\n\n// WriteShallowPlaceholder writes sufficient metadata into the placeholder\n// file associated with path so that it can be roundtripped through\n// snapshot/restore without needing to be realized in the local\n// filesystem.\n// TODO(rjk): Should the placeholder use the complete fs.Entry?\nfunc WriteShallowPlaceholder(path string, de *snapshot.DirEntry) (string, error) {\n\tbuffy := &bytes.Buffer{}\n\tencoder := json.NewEncoder(buffy)\n","sourceCodeStart":13,"sourceCodeEnd":49,"githubUrl":"https://github.com/kopia/kopia/blob/82495e54b584c1ef6073c9e1be048f57f8aef078/fs/localfs/shallow_fs.go#L13-L49","documentation":"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\".","triggerScenarios":"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.","commonSituations":"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.","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"],"exampleFix":"// before\nmp, err := localfs.WriteShallowPlaceholder(destPath, de) // fails: dest on read-only fs\n// after\nif test -w parent; then ... fi — in Go:\nif err := os.MkdirAll(filepath.Dir(destPath), 0o755); err != nil {\n\treturn fmt.Errorf(\"destination %q not writable: %w\", destPath, err)\n}\nmp, err := localfs.WriteShallowPlaceholder(destPath, de)","handlingStrategy":"validation","validationCode":"parent := filepath.Dir(path)\nif err := unix.Access(parent, unix.W_OK); err != nil {\n\treturn fmt.Errorf(\"destination %q not writable: %w\", parent, err)\n}\nif fi, err := os.Lstat(path + \".kopia-entry\"); err == nil && !fi.IsDir() {\n\treturn fmt.Errorf(\"%q exists and is not a directory\", path+\".kopia-entry\")\n}","typeGuard":null,"tryCatchPattern":"mp, err := localfs.WriteShallowPlaceholder(path, de)\nif err != nil {\n\tif os.IsPermission(errors.Cause(err)) {\n\t\treturn fmt.Errorf(\"cannot create placeholder dir for %q: permission denied\", path)\n\t}\n\treturn fmt.Errorf(\"placeholder %q: %w\", path, err)\n}","preventionTips":["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"],"tags":["filesystem","localfs","shallow-placeholder","mkdir"],"backgroundTag":"mkdir-permission-denied","analyzedSha":"82495e54b584c1ef6073c9e1be048f57f8aef078","analyzedAt":"2026-09-07T20:35:21.689Z","contentChangedAt":"2026-09-07T20:35:21.689Z","schemaVersion":2},"datasetVersion":"2026-09-17T15:17:12.973Z"}