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

  1. Filter entries: only call WriteShallowPlaceholder for files and directories; handle symlinks/other types separately (e.g. recreate the symlink directly)
  2. Check de.Type before invoking the placeholder writer and skip unsupported types
  3. 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

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


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)