kopia/kopia · error
unsupported entry type
Error message
unsupported entry type: %v
What it means
placeholderPath only supports snapshot.EntryTypeFile and snapshot.EntryTypeDirectory. If WriteShallowPlaceholder is called for a symlink, device, socket, or any other entry type, it returns this errors.Errorf because placeholder files are not defined for those types.
Solutions
- Filter entries: only call WriteShallowPlaceholder for files and directories; handle symlinks/other types separately (e.g. recreate the symlink directly)
- Check de.Type before invoking the placeholder writer and skip unsupported types
- If symlinks should be supported, update the calling code path rather than this library function
Example fix
// before
for _, de := range dirEntries {
localfs.WriteShallowPlaceholder(dest, de) // panics on symlinks
}
// after
for _, de := range dirEntries {
switch de.Type {
case snapshot.EntryTypeFile, snapshot.EntryTypeDirectory:
localfs.WriteShallowPlaceholder(dest, de)
default:
// recreate symlinks/other types directly
copyNonPlaceholderEntry(dest, de)
}
} Defensive patterns
Strategy: type-guard
Validate before calling
switch de.Type {
case snapshot.EntryTypeFile, snapshot.EntryTypeDirectory:
// OK to write placeholder
default:
return fmt.Errorf("no placeholder support for type %v", de.Type)
} Type guard
func placeholderSupported(t snapshot.EntryType) bool {
return t == snapshot.EntryTypeFile || t == snapshot.EntryTypeDirectory
} Try / catch
if !placeholderSupported(de.Type) {
return handleNonPlaceholder(de) // recreate symlink/device directly
}
if _, err := localfs.WriteShallowPlaceholder(path, de); err != nil {
return fmt.Errorf("placeholder %q: %w", path, err)
} Prevention
- Check de.Type before writing placeholders
- Handle symlinks by recreating them rather than placeholdering
- Keep placeholder writing restricted to file/dir entries in your pipeline
- Document that shallow placeholders apply only to files and directories
When it happens
Trigger: Calling WriteShallowPlaceholder with a *snapshot.DirEntry whose Type is EntryTypeSymlink, EntryTypeDevice, EntryTypeSocket, etc. — e.g. when walking a source tree that contains symlinks or devices and writing placeholders for every entry.
Common situations: Copy/restore pipelines that blindly call writeShallowEntry on all DirEntries including symlinks; snapshot entries produced on Unix with device nodes being replayed through the shallow-placeholder API.
Understand the failure class
Background: UnsupportedOperationException and "is not supported" errors: when a library deliberately refuses a call — this error's family across 30 libraries.
Related errors
- error writing placeholder to
- placeholderPath dir creation
- computing placeholder path
- error reading directory
- json encoding DirEntry
AI-assisted analysis of kopia/kopia@82495e54b5 (2026-09-07).
Data as JSON: /api/errors/bbc1e2356a68ab77.
Report an issue: GitHub.
Appendix: source
Thrown at fs/localfs/shallow_fs.go:37
// 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)
if err := encoder.Encode(de); err != nil {
return "", errors.Wrapf(err, "json encoding DirEntry")
}
mp, err := placeholderPath(path, de.Type)
if err != nil {View on GitHub (pinned to 82495e54b5)