{"record":{"id":"95ed4f491079e832","repo":"dagger/dagger","slug":"missing-persisted-s-snapshot-link-role-q-for-res","errorCode":null,"errorMessage":"missing persisted %s snapshot link role %q for result %d","messagePattern":"missing persisted (.+?) snapshot link role %q for result (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"core/persisted_object.go","lineNumber":136,"sourceCode":"\t\treturn dagql.PersistedSnapshotRefLink{}, fmt.Errorf(\"load persisted %s snapshot link: zero result ID\", label)\n\t}\n\tif _, err := persistedDecodeQuery(dag); err != nil {\n\t\treturn dagql.PersistedSnapshotRefLink{}, fmt.Errorf(\"load persisted %s snapshot link query: %w\", label, err)\n\t}\n\tcache, err := dagql.EngineCache(ctx)\n\tif err != nil {\n\t\treturn dagql.PersistedSnapshotRefLink{}, fmt.Errorf(\"load persisted %s snapshot link cache: %w\", label, err)\n\t}\n\tlinks, err := cache.PersistedSnapshotLinksByResultID(ctx, resultID)\n\tif err != nil {\n\t\treturn dagql.PersistedSnapshotRefLink{}, fmt.Errorf(\"load persisted %s snapshot link: %w\", label, err)\n\t}\n\tfor _, link := range links {\n\t\tif link.Role == role {\n\t\t\treturn link, nil\n\t\t}\n\t}\n\treturn dagql.PersistedSnapshotRefLink{}, fmt.Errorf(\"missing persisted %s snapshot link role %q for result %d\", label, role, resultID)\n}\n\nfunc loadPersistedSnapshotLinksByResultID(ctx context.Context, dag *dagql.Server, resultID uint64, label string) ([]dagql.PersistedSnapshotRefLink, error) {\n\tif resultID == 0 {\n\t\treturn nil, fmt.Errorf(\"load persisted %s snapshot links: zero result ID\", label)\n\t}\n\tif _, err := persistedDecodeQuery(dag); err != nil {\n\t\treturn nil, fmt.Errorf(\"load persisted %s snapshot links query: %w\", label, err)\n\t}\n\tcache, err := dagql.EngineCache(ctx)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"load persisted %s snapshot links cache: %w\", label, err)\n\t}\n\tlinks, err := cache.PersistedSnapshotLinksByResultID(ctx, resultID)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"load persisted %s snapshot links: %w\", label, err)\n\t}\n\treturn links, nil","sourceCodeStart":118,"sourceCodeEnd":154,"githubUrl":"https://github.com/dagger/dagger/blob/82ba2681dbe30d3547a1dc50ea495900ab5b6047/core/persisted_object.go#L118-L154","documentation":"The cache returned snapshot links for the result ID, but none matched the requested role string. The persisted record exists but lacks a link for the specific role (e.g. input vs output snapshot) the decoder needs, indicating an incomplete or differently-versioned persisted record.","triggerScenarios":"loadPersistedSnapshotLinkByResultID iterating links and finding no link.Role == role when called from DecodePersistedObject or loadPersistedImmutableSnapshotByResultID — e.g. a payload persisted by an older version that didn't record the requested role.","commonSituations":"Version drift between the code that persisted the payload and the code decoding it (role names or roles recorded changed); manual payload construction omitting a role; role string typo in custom tooling.","solutions":["Verify the persisted payload was written by a version that records the requested role; re-persist if not.","Check which roles exist for the result ID and use the correct role string.","Handle role absence gracefully for legacy payloads (skip snapshot or backfill).","Confirm the role constant used at persist time matches the one at decode time."],"exampleFix":"// before\nlink, err := loadPersistedSnapshotLinkByResultID(ctx, dag, id, \"container\", roleOutputSnapshot)\n// after\nlinks, err := loadPersistedSnapshotLinksByResultID(ctx, dag, id, \"container\")\nif len(links) == 0 { /* legacy payload: proceed without snapshot */ }","handlingStrategy":"fallback","validationCode":"links, err := cache.PersistedSnapshotLinksByResultID(ctx, resultID)\nif err == nil && !hasRole(links, role) {\n\t// use legacy path or backfill before decode\n}","typeGuard":"func hasRole(links []dagql.PersistedSnapshotRefLink, role string) bool {\n\tfor _, l := range links {\n\t\tif l.Role == role { return true }\n\t}\n\treturn false\n}","tryCatchPattern":"err := decodePersistedObject(ctx, dag, id)\nif err != nil && strings.Contains(err.Error(), \"snapshot link role\") {\n\t// decode without snapshot or migrate the payload\n}","preventionTips":["Persist payloads with all roles the decoder expects.","Keep producer and decoder versions in sync on role names.","Support legacy payloads missing newer roles.","Share role constants, not string literals."],"tags":["go","dagger","snapshot","version-drift"],"backgroundTag":"missing-snapshot-reference","analyzedSha":"82ba2681dbe30d3547a1dc50ea495900ab5b6047","analyzedAt":"2026-09-05T07:21:37.930Z","contentChangedAt":"2026-09-05T07:21:37.930Z","schemaVersion":2},"datasetVersion":"2026-09-12T12:17:11.808Z"}