kopia/kopia · error
unable to encode directory JSON
Error message
unable to encode directory JSON
What it means
WriteDirManifest could not JSON-encode the DirManifest into the repository object writer, so the rewritten directory manifest was not persisted and object.EmptyID is returned. Callers (processDirectoryEntries, uploads, rewrites) surface this as a failure to write the directory.
Solutions
- Check the inner wrapped error; if it is an io.Writer error, treat it as an object-write/storage problem and check repository health.
- Ensure DirManifestBuilder was populated with valid DirEntry values (no nil pointers or corrupt ObjectIDs).
- Upgrade Kopia if a built-in type fails to marshal — for standard structs this indicates a bug.
- Retry the write after resolving any transient storage issues; content-addressed writes are safe to retry.
Defensive patterns
Strategy: validation
Validate before calling
if len(dirManifest.Entries) == 0 && !allowEmpty { return errors.New("refusing to write empty dir manifest") } Type guard
func writableManifest(dm snapshot.DirManifest) bool {
for _, e := range dm.Entries {
if e == nil || e.ObjectID == "" { return false }
}
return true
} Try / catch
oid, err := snapshotfs.WriteDirManifest(ctx, rep, prevOID, dm, comp)
if err != nil {
if strings.Contains(err.Error(), "unable to encode directory JSON") {
log.Printf("manifest encoding failed: %+v", err)
}
return object.EmptyID, err
} Prevention
- Populate DirManifestBuilder only with fully valid DirEntry values.
- Upgrade Kopia if built-in manifest types fail to serialize (library bug).
- Check object-writer health; encoder errors often mask storage write failures.
- Keep directory entry counts reasonable; split pathological trees before rewriting.
When it happens
Trigger: json.NewEncoder(writer).Encode(dirManifest) returns an error inside WriteDirManifest — the DirManifest struct failed to serialize before being uploaded as a directory object.
Common situations: A DirManifest containing entries with data that breaks JSON encoding (custom marshaler bugs, extremely deep/huge manifests hitting resource limits), or an object-writer-level fault surfaced through the encoder's io.Writer.
Understand the failure class
Background: json.Marshal / "failed to marshal" errors in Go: why "unsupported type" happens and how to fix it — this error's family across 22 libraries.
Related errors
- error writing stub contents
- unable to parse manifest
- unable to unmarshal
- can't parse format blob
- cannot save manifest
AI-assisted analysis of kopia/kopia@82495e54b5 (2026-09-07).
Data as JSON: /api/errors/b5859740f6bd7b2e.
Report an issue: GitHub.
Appendix: source
Thrown at snapshot/snapshotfs/dir_writer.go:27
"github.com/kopia/kopia/repo"
"github.com/kopia/kopia/repo/compression"
"github.com/kopia/kopia/repo/object"
"github.com/kopia/kopia/snapshot"
)
// WriteDirManifest writes a directory manifest to the repository and returns the object ID.
func WriteDirManifest(ctx context.Context, rep repo.RepositoryWriter, dirRelativePath string, dirManifest *snapshot.DirManifest, metadataComp compression.Name) (object.ID, error) {
writer := rep.NewObjectWriter(ctx, object.WriterOptions{
Description: "DIR:" + dirRelativePath,
Prefix: objectIDPrefixDirectory,
Compressor: metadataComp,
MetadataCompressor: metadataComp,
})
defer writer.Close() //nolint:errcheck
if err := json.NewEncoder(writer).Encode(dirManifest); err != nil {
return object.EmptyID, errors.Wrap(err, "unable to encode directory JSON")
}
oid, err := writer.Result()
if err != nil {
return object.EmptyID, errors.Wrap(err, "unable to write directory")
}
return oid, nil
}
View on GitHub (pinned to 82495e54b5)