dagger/dagger · error
decode persisted directory payload: unsupported form %q
Error message
decode persisted directory payload: unsupported form %q
What it means
Thrown when a persisted Directory payload has a Form value the decoder does not recognize (neither snapshot nor lazy). The decoder is a strict state machine over the persisted forms, so any unknown form — typically from a newer or older schema version — is rejected rather than misinterpreted. This protects against silently returning a wrong directory state.
Source
Thrown at core/directory.go:324
case persistedDirectoryFormSnapshot:
snapshot, err := loadPersistedImmutableSnapshotByResultID(ctx, dag, resultID, "directory", snapshotRole)
if err != nil {
return nil, err
}
dir.Snapshot.setValue(snapshot)
return dir, nil
case persistedDirectoryFormLazy:
if persisted.LazyKind == "" {
return nil, fmt.Errorf("decode persisted directory payload: missing lazy kind")
}
lazy, err := decodePersistedDirectoryLazy(ctx, dag, persisted.LazyKind, persisted.LazyJSON)
if err != nil {
return nil, err
}
dir.Lazy = lazy
return dir, nil
default:
return nil, fmt.Errorf("decode persisted directory payload: unsupported form %q", persisted.Form)
}
}
func (*Directory) DecodePersistedObject(ctx context.Context, dag *dagql.Server, resultID uint64, _ *dagql.ResultCall, payload json.RawMessage) (dagql.Typed, error) {
return decodePersistedDirectoryWithSnapshotRole(ctx, dag, resultID, payload, "snapshot")
}
func loadCanonicalScratchDirectory(ctx context.Context) (string, bkcache.ImmutableRef, error) {
query, err := CurrentQuery(ctx)
if err != nil {
return "", nil, fmt.Errorf("load canonical scratch directory: %w", err)
}
scratchSnapshot, err := query.SnapshotManager().Scratch(ctx)
if err != nil {
return "", nil, err
}
return "/", scratchSnapshot, nil
}View on GitHub (pinned to 82ba2681db)
Solutions
- Clear the engine cache and re-run so the directory is re-persisted with a form the current decoder understands
- Align engine and CLI versions (the payload schema is version-coupled)
- If writing payloads, only emit the registered form constants: "snapshot" or "lazy"
Example fix
// before
payload := persistedDirectoryPayload{Form: "directory_v2"}
// after
payload := persistedDirectoryPayload{Form: "lazy", LazyKind: kind, LazyJSON: blob} Defensive patterns
Strategy: validation
Validate before calling
var p persistedDirectoryPayload
if err := json.Unmarshal(payload, &p); err != nil { return err }
if p.Form != "snapshot" && p.Form != "lazy" {
return fmt.Errorf("unknown persisted directory form %q", p.Form)
} Type guard
func isKnownDirectoryForm(f string) bool {
return f == "snapshot" || f == "lazy"
} Prevention
- Only emit registered form constants when persisting
- Version-stamp persisted payloads and reject unknown versions early
- Clear stale caches after upgrading the engine
When it happens
Trigger: decodePersistedDirectoryWithSnapshotRole reads persisted.Form that is not persistedDirectoryFormSnapshot or persistedDirectoryFormLazy — e.g. empty form field, cache entry written by a different Dagger version with added forms, or corrupt/edited cache data.
Common situations: Engine/CLI version skew (payload written by a version with newer forms read by an older decoder); corrupted persisted-result cache; manual cache manipulation.
Related errors
- decode persisted directory payload: missing lazy kind
- decode persisted directory lazy payload: unsupported lazy ki
- after ID: %w
- marshal pending container directory value: %w
- marshal pending container file value: %w
AI-assisted analysis of dagger/dagger@82ba2681db (2026-09-05).
Data as JSON: /api/errors/b478d897e1d643bd.
Report an issue: GitHub.