{"record":{"id":"6fe1a7328a8c3fa4","repo":"toeverything/AFFiNE","slug":"databaseblockerror","errorCode":"DatabaseBlockError","errorMessage":"Unknown view type: ${type}","messagePattern":"Unknown view type: (.+?)","errorType":"exception","errorClass":"BlockSuiteError","httpStatus":null,"severity":"error","filePath":"blocksuite/affine/blocks/database/src/data-source.ts","lineNumber":606,"sourceCode":"  viewDataGet(viewId: string): DataViewDataType | undefined {\n    return this.viewDataList$.value.find(data => data.id === viewId)!;\n  }\n\n  viewDataMoveTo(id: string, position: InsertToPosition): void {\n    moveViewTo(this._model, id, position);\n  }\n\n  viewDataUpdate<ViewData extends DataViewDataType>(\n    id: string,\n    updater: (data: ViewData) => Partial<ViewData>\n  ): void {\n    updateView(this._model, id, updater);\n  }\n\n  viewMetaGet(type: string): ViewMeta {\n    const view = databaseBlockViewMap[type];\n    if (!view) {\n      throw new BlockSuiteError(\n        ErrorCode.DatabaseBlockError,\n        `Unknown view type: ${type}`\n      );\n    }\n    return view;\n  }\n\n  viewMetaGetById(viewId: string): ViewMeta | undefined {\n    const view = this.viewDataGet(viewId);\n    if (!view) {\n      return;\n    }\n    return this.viewMetaGet(view.mode);\n  }\n}\n\nexport const databaseViewInitTemplate = (\n  datasource: DatabaseBlockDataSource,","sourceCodeStart":588,"sourceCodeEnd":624,"githubUrl":"https://github.com/toeverything/AFFiNE/blob/b4c8548c09da21b2898443559a5b846f0ccf5dd8/blocksuite/affine/blocks/database/src/data-source.ts#L588-L624","documentation":"Framework.addFactory keys registrations by (scope stack, identifierName, variant). Registering a second factory for the exact same combination without the override flag throws DuplicateDefinitionError — the container treats double registration as a programming error rather than silently replacing the first implementation, which would hide order-dependent bugs.","triggerScenarios":"Calling framework.impl(Storage, LocalStorage) twice with the default variant; two modules both registering the same interface and both being imported; a plugin/test setup function that calls impl() running again on the same Framework (HMR reload, repeated beforeEach) without cleanup; registering the same identifier under the same scope stack via framework.scope(ScopeA).impl(...).","commonSituations":"Hot module reload re-executing registration modules; test setup helpers that add mocks and are invoked per test against a shared Framework; copy-pasted registrations; merging two modules that each register a shared service.","solutions":["If the second registration should win, use framework.override(Identifier, Impl) — it replaces the existing factory (override(Identifier, null) removes it)","If both implementations are needed simultaneously, register them as variants: framework.impl(Storage('local'), LocalStorage) and framework.impl(Storage('session'), SessionStorage)","If the duplicate is accidental, delete the second registration or guard setup so it runs once per Framework instance (module-level flag, or build a fresh Framework per test)"],"exampleFix":"// before\nfw.impl(Storage, LocalStorage);\nfw.impl(Storage, LocalStorage); // DuplicateDefinitionError: [Storage] already exists\n\n// after\nfw.impl(Storage, LocalStorage);\nfw.override(Storage, SessionStorage); // intentionally replaces\n// or use variants:\nfw.impl(Storage('session'), SessionStorage);","handlingStrategy":"try-catch","validationCode":"const registered = new Set<string>();\nfunction registerOnce(fw: Framework, id: Identifier<any>, impl: any, key: string) {\n  if (registered.has(key)) {\n    fw.override(id, impl); // second pass replaces instead of throwing\n  } else {\n    fw.impl(id, impl);\n    registered.add(key);\n  }\n}","typeGuard":"null","tryCatchPattern":"try {\n  fw.impl(Storage, LocalStorage);\n} catch (err) {\n  if (err instanceof DuplicateDefinitionError) {\n    fw.override(Storage, LocalStorage); // intentional replacement\n  } else {\n    throw err;\n  }\n}","preventionTips":["Make registration modules idempotent: guard with a module-level Set or run setup once per Framework instance","Use framework.override() whenever a later registration is meant to win","Use variants (Identifier('name')) for coexisting implementations instead of double-registering the default variant","Build a fresh Framework per test to avoid cross-test duplicate registrations"],"tags":["dependency-injection","registration","duplicate","variant"],"backgroundTag":"duplicate-di-registration","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"}