kopia/kopia · error

unable to read symlink

Error message

unable to read symlink

What it means

Raised in uploadSymlinkInternal when fs.Symlink.Readlink fails while snapshotting a symlink: the OS returned an error reading the link target — commonly because the symlink is dangling in a way the filesystem reports (e.g. path-based walkers on Windows), the entry was deleted concurrently with the walk, or platform-specific readlink limitations. The relative path being uploaded identifies the faulting entry.

Solutions

  1. Check whether the symlink still exists on disk and re-run the snapshot if it was transiently removed
  2. On Windows, ensure Developer Mode is enabled or the process runs elevated so symlink information is accessible
  3. Ignore symlink read errors via the uploader's ignore-permissions/readlier options when symlink targets are not required
  4. Re-run with caching disabled if a stale directory cache points at since-deleted symlinks
Defensive patterns

Strategy: retry

When it happens

Trigger: Thrown at snapshot/upload/upload.go:312 when the library encounters an invalid state.

Common situations: See trigger scenarios.


AI-assisted analysis of kopia/kopia@82495e54b5 (2026-09-07). Data as JSON: /api/errors/20c1080309b2021c. Report an issue: GitHub.

Appendix: source

Thrown at snapshot/upload/upload.go:312

	de.FileSize = written

	atomic.AddInt32(&u.stats.TotalFileCount, 1)
	atomic.AddInt64(&u.stats.TotalFileSize, de.FileSize)

	return de, nil
}

func (u *Uploader) uploadSymlinkInternal(ctx context.Context, relativePath string, f fs.Symlink, metadataComp compression.Name) (dirEntry *snapshot.DirEntry, ret error) {
	u.Progress.HashingFile(relativePath)

	defer func() {
		u.Progress.FinishedFile(relativePath, ret)
	}()
	defer u.Progress.FinishedHashingFile(relativePath, f.Size())

	target, err := f.Readlink(ctx)
	if err != nil {
		return nil, errors.Wrap(err, "unable to read symlink")
	}

	writer := u.repo.NewObjectWriter(ctx, object.WriterOptions{
		Description:        "SYMLINK:" + f.Name(),
		MetadataCompressor: metadataComp,
	})
	defer writer.Close() //nolint:errcheck

	written, err := u.copyWithProgress(writer, bytes.NewBufferString(target))
	if err != nil {
		return nil, err
	}

	r, err := writer.Result()
	if err != nil {
		return nil, errors.Wrap(err, "unable to get result")
	}

View on GitHub (pinned to 82495e54b5)