{"record":{"id":"93d228ef60f15f92","repo":"toeverything/AFFiNE","slug":"databaseblockerror-93d228","errorCode":"DatabaseBlockError","errorMessage":"unexpected type unify, type var reference","messagePattern":"unexpected type unify, type var reference","errorType":"exception","errorClass":"BlockSuiteError","httpStatus":null,"severity":"error","filePath":"blocksuite/affine/data-view/src/core/logical/type-variable.ts","lineNumber":36,"sourceCode":"}\n\nexport class TypeVarReferenceInstance<\n  Name extends string = string,\n> implements TypeInstance {\n  readonly _validate = unknownSchema;\n\n  readonly _valueType = undefined as unknown;\n\n  readonly name = '__TypeVarReference';\n\n  constructor(readonly varName: Name) {}\n\n  subst(ctx: TypeVarContext): void | TypeInstance {\n    return ctx[this.varName]?.type;\n  }\n\n  unify(_ctx: TypeVarContext, _type: TypeInstance, _unify: Unify): boolean {\n    throw new BlockSuiteError(\n      ErrorCode.DatabaseBlockError,\n      'unexpected type unify, type var reference'\n    );\n  }\n\n  valueValidate(_value: unknown): _value is unknown {\n    return true;\n  }\n}\n\nexport const tv = {\n  typeVarDefine: {\n    create: <\n      Name extends string = string,\n      Type extends TypeInstance = TypeInstance,\n    >(\n      name: Name,\n      typeConstraint?: Type","sourceCodeStart":18,"sourceCodeEnd":54,"githubUrl":"https://github.com/toeverything/AFFiNE/blob/b4c8548c09da21b2898443559a5b846f0ccf5dd8/blocksuite/affine/data-view/src/core/logical/type-variable.ts#L18-L54","documentation":"Internal invariant of the data-view logical type engine. TypeVarReferenceInstance (type-variable.ts:20-45) is a placeholder produced by tRef(name); it must be substituted with a concrete TypeInstance via subst(TypeVarContext) before type unification. Its unify() always throws 'unexpected type unify, type var reference', meaning a type variable was never bound (its name missing from the context) when unification ran.","triggerScenarios":"Unifying a TypeInstance that is still a __TypeVarReference because ctx[varName] was never defined (subst returned undefined); building logical expressions where tRef('x') has no matching tVar define entry in the TypeVarContext; calling unify directly on a freshly created tRef without substitution.","commonSituations":"Writing custom logical expressions / property type constraints against the data-view type engine; refactoring type-variable plumbing so define and reference names diverge; serialize/deserialize of expressions losing the define side of the context.","solutions":["Ensure every tVarDefine name referenced by tRef has an entry in the TypeVarContext before unifying","Call subst first, verify it returned a concrete type, and only then unify","Use the built-in guard tv.typeVarReference.is(type) to reject placeholders before calling unify"],"exampleFix":"// before\nconst ok = unify(ctx, tRef('T'), concreteType); // throws if 'T' unbound\n\n// after\nconst resolved = substitute(tRef('T'), ctx);\nif (!resolved) throw new Error(`unbound type variable T`);","handlingStrategy":"type-guard","validationCode":"import { tv } from './type-variable.js';\n\n// substitute placeholders and verify binding before unify\nconst substResult = typeInstance.subst(typeVarContext);\nif (tv.typeVarReference.is(typeInstance) && !substResult) {\n  throw new Error(`unbound type variable: ${typeInstance.varName}`);\n}","typeGuard":"tv.typeVarReference.is = (type: TypeInstance): type is TypeVarReferenceInstance =>\n  type.name === '__TypeVarReference';\n\n// usage: never call unify on a value passing this guard","tryCatchPattern":"try {\n  unify(ctx, left, right);\n} catch (e) {\n  if (e instanceof BlockSuiteError && e.code === BlockSuiteError.ErrorCode.DatabaseBlockError) {\n    // binding bug: report which type var was left unsubstituted\n  }\n  throw e;\n}","preventionTips":["Always bind a tVarDefine entry for every tRef name before unification","Run subst() to a fixpoint and check for undefined before unify","Treat this throw as an internal assertion failure — fix the caller, don't catch it in production paths"],"tags":["database-block","type-system","internal-invariant","logical-expression"],"backgroundTag":"unbound-type-variable","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"}