{"record":{"id":"5696dfe938fb7479","repo":"dagger/dagger","slug":"lookup-cache-for-digests-hit-missing-shared-resul","errorCode":null,"errorMessage":"lookup cache for digests: hit missing shared result ID","messagePattern":"lookup cache for digests: hit missing shared result ID","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"dagql/cache.go","lineNumber":4652,"sourceCode":"\t\tc.traceLookupMissNoMatch(ctx, recipeDigest.String(), false, -1, \"\", 0)\n\t\tc.egraphMu.Unlock()\n\t\treturn nil, false, nil\n\t}\n\n\thitRes.expiresAtUnix = mergeSharedResultExpiryUnix(\n\t\thitRes.expiresAtUnix,\n\t\tcandidateSharedResultExpiryUnix(nowUnix, 0),\n\t)\n\ttouchSharedResultLastUsed(hitRes, now.UnixNano())\n\tretRes := Result[Typed]{\n\t\tshared:   hitRes,\n\t\thitCache: true,\n\t}\n\tc.traceLookupHit(ctx, recipeDigest.String(), hitRes, match.termDigest)\n\thitShared := retRes.cacheSharedResult()\n\tif hitShared == nil || hitShared.id == 0 {\n\t\tc.egraphMu.Unlock()\n\t\treturn nil, false, fmt.Errorf(\"lookup cache for digests: hit missing shared result ID\")\n\t}\n\n\t_, trackedCount, err := c.acquireSessionResultLocked(ctx, sessionID, hitShared)\n\tc.egraphMu.Unlock()\n\tif err != nil {\n\t\treturn nil, false, err\n\t}\n\n\tloadedHit, err := c.ensurePersistedHitValueLoaded(ctx, resolver, retRes)\n\tif err != nil {\n\t\treturn nil, false, err\n\t}\n\tif c.traceEnabled() {\n\t\tc.traceSessionResultTracked(ctx, sessionID, loadedHit, true, trackedCount)\n\t}\n\treturn loadedHit, true, nil\n}\n","sourceCodeStart":4634,"sourceCodeEnd":4670,"githubUrl":"https://github.com/dagger/dagger/blob/82ba2681dbe30d3547a1dc50ea495900ab5b6047/dagql/cache.go#L4634-L4670","documentation":"After a digest-based cache lookup finds a candidate hit, the result must have a shared result with a valid nonzero ID (its identity in the egraph/cache bookkeeping). If hitRes has no shared result or its id is 0, the cache's internal invariants are violated — the lookup matched a malformed entry — and the method returns this error while releasing the egraph lock.","triggerScenarios":"A digest-keyed lookup (Cache.lookupCacheForDigests) selects a candidate via selectLookupCandidateForSessionLocked whose shared result is nil or whose id was never assigned (0). This indicates corrupted or improperly published cache state rather than a caller mistake.","commonSituations":"A result was inserted into lookup structures without going through the normal publication path that assigns IDs; persistence/restore bugs where rehydrated results lack IDs; race or bug in result canonicalization leaving half-initialized shared results addressable by digest.","solutions":["Report/investigate as a cache invariant bug: find how a result without an ID became a lookup candidate (check the insert/publish path and any persistence rehydration code).","Ensure all results are published through initCompletedResult / the normal sharedResult creation path that assigns ids.","If results are rehydrated from persistence, verify IDs are restored or reassigned before the entries are added to digest indexes.","As a workaround, clear/rebuild the affected cache state so malformed entries are dropped."],"exampleFix":"// before (publisher that inserts a result without assigning an ID)\nshared := &sharedResult{}\nc.indexDigestLocked(recipeDigest, shared)\n// after\nshared := &sharedResult{}\nshared.id = c.nextResultIDLocked() // assign identity before indexing\nif shared == nil || shared.id == 0 { return fmt.Errorf(\"refusing to index result without ID\") }\nc.indexDigestLocked(recipeDigest, shared)","handlingStrategy":"type-guard","validationCode":null,"typeGuard":"func hasValidSharedResult(res dagql.AnyResult) bool {\n    shared := res.CacheSharedResult()\n    return shared != nil && shared.ID != 0\n}","tryCatchPattern":"res, hit, err := cache.LookupCacheForDigests(ctx, sessionID, resolver, dg, extras)\nif err != nil {\n    if strings.Contains(err.Error(), \"hit missing shared result ID\") {\n        // treat as a cache miss and re-execute the call\n        return executeFresh(ctx, dg)\n    }\n    return err\n}","preventionTips":["Publish results only through the normal initCompletedResult path that assigns IDs.","Validate rehydrated/persisted results have nonzero IDs before adding them to digest indexes.","On this error at runtime, fall back to re-executing the call rather than retrying the lookup."],"tags":["go","dagql","cache","invariant"],"backgroundTag":"cache-invariant-violation","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"}