{"record":{"id":"b0633aacc2b976b8","repo":"toeverything/AFFiNE","slug":"databaseblockerror-b0633a","errorCode":"DatabaseBlockError","errorMessage":"View ${viewId} not found","messagePattern":"View (.+?) not found","errorType":"exception","errorClass":"BlockSuiteError","httpStatus":null,"severity":"error","filePath":"blocksuite/affine/data-view/src/core/data-view.ts","lineNumber":67,"sourceCode":"      data: {\n        view: SingleView;\n        rowId: string;\n      }\n    ) => Promise<void>;\n  };\n};\n\nexport class DataViewRootUILogic {\n  private get dataSource() {\n    return this.config.dataSource;\n  }\n  private get viewManager() {\n    return this.dataSource.viewManager;\n  }\n  private createDataViewUILogic(viewId: string): DataViewUILogicBase {\n    const view = this.viewManager.viewGet(viewId);\n    if (!view) {\n      throw new BlockSuiteError(\n        BlockSuiteError.ErrorCode.DatabaseBlockError,\n        `View ${viewId} not found`\n      );\n    }\n\n    const pcLogic = view.meta.renderer.pcLogic;\n    const mobileLogic = view.meta.renderer.mobileLogic;\n    const logic = (IS_MOBILE ? mobileLogic : pcLogic) ?? pcLogic;\n\n    return new (logic(view))(this, view);\n  }\n  private readonly _viewsCache = new Map<\n    string,\n    { mode: string; logic: DataViewUILogicBase }\n  >();\n\n  private readonly views$ = computed(() => {\n    const viewDataList = this.dataSource.viewDataList$.value;","sourceCodeStart":49,"sourceCodeEnd":85,"githubUrl":"https://github.com/toeverything/AFFiNE/blob/b4c8548c09da21b2898443559a5b846f0ccf5dd8/blocksuite/affine/data-view/src/core/data-view.ts#L49-L85","documentation":"Thrown by DataViewRootUILogic.createDataViewUILogic (blocksuite/affine/data-view/src/core/data-view.ts:64-71) when viewManager.viewGet(viewId) returns undefined. The data-view widget builds a per-view UI logic for every id in dataSource.viewDataList$; if the view manager cannot resolve an id to a view meta (renderer, name), database-block rendering aborts with this DatabaseBlockError. It almost always means a dangling view id: the id list and the actual view storage are out of sync.","triggerScenarios":"A view is deleted while the views$ computed is mid-update (reactive race), so viewDataList$ still holds a removed id; restoring a database-block snapshot whose views array references a view id that no longer exists; calling viewManager.viewGet / mounting the data-view with a stale or hand-crafted id from untrusted JSON.","commonSituations":"Rapid view deletion during a reactive re-render; corrupted or hand-edited database block JSON; collaborative editing where a remote peer deletes a view the local client is rendering; block migrations that regenerate view ids without pruning references.","solutions":["Check dataSource.viewManager.viewGet(viewId) before rendering and skip/prune the stale id instead of constructing the UI logic","Delete the stale entry from the block's view list (viewDelete or equivalent) so viewDataList$ and the view manager stay in sync","When restoring old snapshots, migrate first: drop view entries whose id no longer resolves, or rebuild a default view","Wrap mount/render in try-catch for BlockSuiteError with code DatabaseBlockError and fall back to the first resolvable view"],"exampleFix":"// before\nconst logic = this.createDataViewUILogic(viewData.id); // throws 'View xxx not found'\n\n// after\nconst view = this.viewManager.viewGet(viewData.id);\nif (!view) {\n  this.viewManager.viewDelete(viewData.id); // prune the dangling id\n  return null;\n}","handlingStrategy":"validation","validationCode":"const isViewIdResolvable = (dataSource: DataSource, viewId: string): boolean =>\n  !!dataSource.viewManager.viewGet(viewId);\n\n// prune before rendering\nconst validViewData = dataSource.viewDataList$.value.filter(v =>\n  isViewIdResolvable(dataSource, v.id)\n);","typeGuard":"function isResolvedView(view: SingleView | undefined): view is SingleView {\n  return view !== undefined;\n}","tryCatchPattern":"try {\n  const logic = this.createDataViewUILogic(viewId);\n} catch (e) {\n  if (e instanceof BlockSuiteError && e.code === BlockSuiteError.ErrorCode.DatabaseBlockError) {\n    // stale view id: remove it from the view list and re-render, do not crash the editor\n    this.viewManager.viewDelete(viewId);\n    return;\n  }\n  throw e;\n}","preventionTips":["Always delete views through the view manager API so id lists and storage update atomically","When loading/restoring snapshots, drop view entries whose ids do not resolve before mounting the data-view","Never construct view ids by string manipulation; use ids from viewDataList$"],"tags":["database-block","data-view","stale-id","reactive-state"],"backgroundTag":"dangling-view-id","analyzedSha":"b4c8548c09da21b2898443559a5b846f0ccf5dd8","analyzedAt":"2026-08-18T21:16:52.546Z","contentChangedAt":"2026-08-18T21:16:52.546Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}