{"record":{"id":"4f6a4421e68df3a2","repo":"moeru-ai/airi","slug":"backgroundstore-activebackgroundurl-no-entry-or","errorCode":null,"errorMessage":"[BackgroundStore] activeBackgroundUrl: No entry or URL found for ID \"${lookupId}\"","messagePattern":"\\[BackgroundStore\\] activeBackgroundUrl: No entry or URL found for ID \"(.+?)\"","errorType":"console","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"packages/stage-ui/src/stores/background.ts","lineNumber":232,"sourceCode":"    // Normalize prefix just in case they stored 'image-journal-xyz'\n    let lookupId = bgId\n    if (bgId.startsWith('image-journal-')) {\n      lookupId = bgId.replace('image-journal-', STORAGE_PREFIX)\n    }\n\n    // Return the reactive URL from our map if it exists and the entry is still valid\n    const entryExists = entries.value.has(lookupId)\n    const url = backgroundUrls[lookupId] ?? null\n\n    // NOTICE: We gate the return on entry existence to ensure deleted backgrounds\n    // (removed from other windows) do not keep rendering via a stale cached URL.\n    if (url && entryExists) {\n      return url\n    }\n\n    const entry = entries.value.get(lookupId)\n    if (!entry) {\n      console.warn(`[BackgroundStore] activeBackgroundUrl: No entry or URL found for ID \"${lookupId}\"`)\n      return null\n    }\n\n    return null // Should have been caught by backgroundUrls check above if entry is valid\n  })\n\n  const getCharacterBackgrounds = computed(() => (characterId?: string) => {\n    const list = Array.from(entries.value.values()).filter((e) => {\n      // Shared (builtin/scene) or Journal/Selfie for specific character\n      return e.type === 'scene' || e.type === 'builtin' || ((e.type === 'journal' || e.type === 'selfie') && characterId && e.characterId === characterId)\n    })\n    return list.map(e => ({\n      ...e,\n      url: backgroundUrls[e.id] ?? null,\n    })).sort((a, b) => b.createdAt - a.createdAt)\n  })\n\n  // List of available backgrounds for the current character","sourceCodeStart":214,"sourceCodeEnd":250,"githubUrl":"https://github.com/moeru-ai/airi/blob/677329427f32468c74b17f3ec47eeca4e05bec65/packages/stage-ui/src/stores/background.ts#L214-L250","documentation":"Warn from the background store's activeBackgroundUrl computed. The active card references a background through extensions.airi.modules.activeBackgroundId (normalized from the 'image-journal-' prefix to the storage prefix), but entries has no record with that ID, so the computed returns null and the scene renders without its background. The entry-existence gate also exists so backgrounds deleted in other windows stop rendering via stale cached blob URLs.","triggerScenarios":"activeBackgroundId points at a deleted journal/selfie background; the store's async initializeStore() has not hydrated entries yet (first render after boot); a cross-window deletion broadcast has not been applied in this window; or profile/card JSON was synced to a machine where the background blobs were never created.","commonSituations":"User deleted a journal image that was set as the active background; duplicated profiles across devices sharing card data but not IndexedDB blobs; races between app startup and the auto-init store; leftover IDs after the image-journal prefix migration.","solutions":["If this fires once at startup, ignore it - hydration finishes asynchronously and the computed re-evaluates","If persistent, reset the stale reference: set extensions.airi.modules.activeBackgroundId to 'none' or to an ID present in getCharacterBackgrounds","Re-create the missing background (re-upload or re-journal the image) so entries.value.has(lookupId) becomes true","Check the BroadcastChannel 'airi:background-sync' flow when multiple windows are open - deletion in another window is intentionally honored here"],"exampleFix":"// before\nconst bgUrl = backgroundStore.activeBackgroundUrl.value\n\n// after: tolerate the hydration window and the deleted case\nconst bgUrl = computed(() =>\n  backgroundStore.loading.value ? null : backgroundStore.activeBackgroundUrl.value,\n)\nwatch(bgUrl, (url) => {\n  if (!url) resetToDefaultScene()\n})","handlingStrategy":"type-guard","validationCode":"if (!backgroundStore.loading.value) {\n  const url = backgroundStore.activeBackgroundUrl.value\n  if (!url) resetToDefaultScene()\n}","typeGuard":"function hasBackgroundEntry(\n  entries: ReadonlyMap<string, unknown>,\n  id: string | undefined | null,\n): id is string {\n  return typeof id === 'string' && id !== 'none' && entries.has(id)\n}","tryCatchPattern":null,"preventionTips":["Clear activeBackgroundId to 'none' whenever the referenced background is deleted","Await store initialization before reading activeBackgroundUrl in non-reactive contexts","Handle a null activeBackgroundUrl in the scene renderer as a supported state, not an error"],"tags":["pinia","store","computed","background","missing-entry","stale-reference"],"backgroundTag":"stale-id-reference","analyzedSha":"677329427f32468c74b17f3ec47eeca4e05bec65","analyzedAt":"2026-08-18T17:29:58.153Z","contentChangedAt":"2026-08-18T17:29:58.153Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}