{"record":{"id":"dca6f1a2c8a3d3a8","repo":"toeverything/AFFiNE","slug":"blob-engine-is-not-initialized","errorCode":null,"errorMessage":"Blob engine is not initialized","messagePattern":"Blob engine is not initialized","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"blocksuite/affine/components/src/resource/resource.ts","lineNumber":166,"sourceCode":"        }\n\n        this.updateState({ ...state, uploading, downloading, errorMessage });\n      });\n\n      return () => subscription.unsubscribe();\n    });\n  }\n\n  async blob() {\n    const blobId = this.blobId$.peek();\n    if (!blobId) return null;\n\n    let blob: Blob | null = null;\n    let errorMessage: string | null = null;\n\n    try {\n      if (!this.engine) {\n        throw new Error('Blob engine is not initialized');\n      }\n\n      blob = (await this.engine.get(blobId)) ?? null;\n\n      if (!blob) errorMessage = `${this.kind} not found`;\n    } catch (err) {\n      console.error(err);\n      errorMessage = `Failed to retrieve ${this.kind}`;\n    }\n\n    if (errorMessage) this.updateState({ errorMessage });\n\n    return blob;\n  }\n\n  async createUrlWith(type?: string) {\n    let blob = await this.blob();\n    if (!blob) return null;","sourceCodeStart":148,"sourceCodeEnd":184,"githubUrl":"https://github.com/toeverything/AFFiNE/blob/26c515e050211269e911f7d9cfe162a26c83ed98/blocksuite/affine/components/src/resource/resource.ts#L148-L184","documentation":"ResourceController manages blob/file/image fetching via a BlobEngine. The engine is optional and is wired in through setEngine(). The blob() method throws 'Blob engine is not initialized' if blob() is invoked before setEngine() has been called.","triggerScenarios":"Constructing `new ResourceController(blobId$)` and calling `.blob()` without first chaining `.setEngine(engine)`. Happens when the controller is used before the sync/blob infrastructure is ready.","commonSituations":"Component lifecycle races where a resource viewer renders before the editor's BlobEngine is registered; integration tests that create a ResourceController in isolation.","solutions":["Always call `controller.setEngine(blobEngine)` before invoking blob().","Defer blob() until the engine is available, e.g. subscribe to the engine-ready signal first.","In tests, inject a mock BlobEngine via setEngine()."],"exampleFix":"// before\nconst ctrl = new ResourceController(blobId$);\nawait ctrl.blob(); // throws\n\n// after\nconst ctrl = new ResourceController(blobId$).setEngine(blobEngine);\nawait ctrl.blob();","handlingStrategy":"type-guard","validationCode":"if (!controller.engine) { /* wait for setEngine or return placeholder */ }","typeGuard":"const hasEngine = (c: ResourceController): boolean => Boolean((c as any).engine);","tryCatchPattern":null,"preventionTips":["Always chain setEngine(engine) right after construction","Delay blob() until the editor's blob engine is registered"],"tags":["blob","resource","initialization","lifecycle"],"backgroundTag":null,"analyzedSha":"26c515e050211269e911f7d9cfe162a26c83ed98","analyzedAt":"2026-08-12T13:15:16.447Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}