{"record":{"id":"fcbf86a05595f98b","repo":"abhigyanpatwari/GitNexus","slug":"diskbackedscopetree-byid-is-unsupported-ingestion","errorCode":null,"errorMessage":"DiskBackedScopeTree.byId is unsupported (INGESTION_EMIT_SCOPES is incompatible with GITNEXUS_DISK_SCOPE_INDEX).","messagePattern":"DiskBackedScopeTree\\.byId is unsupported \\(INGESTION_EMIT_SCOPES is incompatible with GITNEXUS_DISK_SCOPE_INDEX\\)\\.","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"gitnexus/src/storage/scope-index-store.ts","lineNumber":149,"sourceCode":"  /** Decoded shards, most-recently-used last (Map preserves insertion order). */\n  private readonly lru = new Map<string, Map<ScopeId, Scope>>();\n\n  constructor(\n    storagePath: string,\n    skeleton: ReadonlyMap<ScopeId, ScopeSkeletonEntry>,\n    maxResidentShards = 64,\n  ) {\n    this.dir = getScopeIndexStoreDir(storagePath);\n    this.skeleton = skeleton;\n    this.maxResidentShards = Math.max(1, maxResidentShards);\n  }\n\n  get size(): number {\n    return this.skeleton.size;\n  }\n\n  get byId(): ReadonlyMap<ScopeId, Scope> {\n    throw new Error(\n      'DiskBackedScopeTree.byId is unsupported (INGESTION_EMIT_SCOPES is incompatible with GITNEXUS_DISK_SCOPE_INDEX).',\n    );\n  }\n\n  has(id: ScopeId): boolean {\n    return this.skeleton.has(id);\n  }\n\n  getChildren(id: ScopeId): readonly ScopeId[] {\n    return this.skeleton.get(id)?.childIds ?? EMPTY;\n  }\n\n  getScope(id: ScopeId): Scope | undefined {\n    const meta = this.skeleton.get(id);\n    if (meta === undefined) return undefined;\n    return this.loadShard(meta.shard).get(id);\n  }\n","sourceCodeStart":131,"sourceCodeEnd":167,"githubUrl":"https://github.com/abhigyanpatwari/GitNexus/blob/aac7515d2a8c50a1f8f923c6fb77218b333560d6/gitnexus/src/storage/scope-index-store.ts#L131-L167","documentation":"With GITNEXUS_DISK_SCOPE_INDEX set (default off), scopes are persisted to per-file JSON shards and only a resident skeleton (scopeId → shard/parent/childIds) stays in memory — the design that cuts the ~17-20 GB resident scope payload on kernel-scale repos. Consumers must fetch full Scope objects via getScope(id) point lookups; the byId map, which would materialize every Scope at once, is deliberately unsupported in that mode, so accessing it throws immediately, naming the incompatible flag combination.","triggerScenarios":"GITNEXUS_DISK_SCOPE_INDEX is set (memory-constrained indexing of a huge repo) and a code path calls scopeTree.byId expecting the resident Map<ScopeId, Scope> that the default buildScopeTree path provides.","commonSituations":"Enabling the disk scope index for memory, then running an older tool, plugin, or script that iterates [...tree.byId.values()]; a version upgrade introducing a new byId consumer while the env flag stays set in CI.","solutions":["Unset GITNEXUS_DISK_SCOPE_INDEX for runs that need the full resident scope map","Refactor the consumer to the supported surface: has(id), getChildren(id), and getScope(id) point lookups","Gate byId access behind a mode check so both storage modes work","Keep INGESTION_EMIT_SCOPES expectations in sync with the storage mode when configuring both"],"exampleFix":"// before — throws under GITNEXUS_DISK_SCOPE_INDEX\nconst all = [...scopeTree.byId.values()];\n\n// after — works in both modes\nconst ids: ScopeId[] = [];\nconst walk = (id: ScopeId): void => {\n  ids.push(id);\n  scopeTree.getChildren(id).forEach(walk);\n};\nrootIds.forEach(walk);\nconst all = ids.map((id) => scopeTree.getScope(id)!);","handlingStrategy":"validation","validationCode":"if (process.env.GITNEXUS_DISK_SCOPE_INDEX) {\n  throw new Error(\n    'scopeTree.byId is unavailable under GITNEXUS_DISK_SCOPE_INDEX — use getScope()/getChildren()',\n  );\n}\nconst all = [...scopeTree.byId.values()];","typeGuard":"function supportsById(tree: ScopeTree): boolean {\n  return (tree as { dir?: unknown }).dir === undefined; // DiskBackedScopeTree carries .dir\n}","tryCatchPattern":"try {\n  useAllScopes([...scopeTree.byId.values()]);\n} catch (e) {\n  if (e instanceof Error && e.message.includes('DiskBackedScopeTree.byId')) {\n    useAllScopes(allScopeIds().map((id) => scopeTree.getScope(id)!));\n    return;\n  }\n  throw e;\n}","preventionTips":["Never iterate byId in code that must run under GITNEXUS_DISK_SCOPE_INDEX — use getScope point lookups","Gate byId access behind an env/instance check so both storage modes keep working","Document which flag combinations your tool supports and fail fast with a clear message"],"tags":["configuration","env-vars","feature-flag","storage","scopes"],"backgroundTag":"incompatible-feature-flags","analyzedSha":"aac7515d2a8c50a1f8f923c6fb77218b333560d6","analyzedAt":"2026-08-20T23:29:22.980Z","contentChangedAt":"2026-08-20T23:29:22.980Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}