{"record":{"id":"f99d1037c0fdefa2","repo":"toeverything/AFFiNE","slug":"no-metadata-provided","errorCode":null,"errorMessage":"No metadata provided","messagePattern":"No metadata provided","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"warning","filePath":"packages/backend/server/src/core/doc/writer.ts","lineNumber":216,"sourceCode":"    return { success: true };\n  }\n\n  /**\n   * Updates document metadata (currently title only).\n   *\n   * @param workspaceId - The workspace ID\n   * @param docId - The document ID to update\n   * @param meta - Metadata updates\n   * @param editorId - Optional editor ID for tracking\n   */\n  async updateDocMeta(\n    workspaceId: string,\n    docId: string,\n    meta: { title?: string },\n    editorId?: string\n  ): Promise<UpdateDocResult> {\n    if (meta.title === undefined) {\n      throw new Error('No metadata provided');\n    }\n\n    this.logger.debug(`Updating doc meta ${docId} in workspace ${workspaceId}`);\n\n    const existingDoc = await this.storage.getDoc(workspaceId, docId);\n    if (!existingDoc?.bin) {\n      throw new NotFoundException(`Document ${docId} not found`);\n    }\n\n    const rootDoc = await this.storage.getDoc(workspaceId, workspaceId);\n    if (!rootDoc?.bin) {\n      throw new NotFoundException(\n        `Workspace ${workspaceId} not found or has no root document`\n      );\n    }\n\n    const existingBinary = Buffer.isBuffer(existingDoc.bin)\n      ? existingDoc.bin","sourceCodeStart":198,"sourceCodeEnd":234,"githubUrl":"https://github.com/toeverything/AFFiNE/blob/26c515e050211269e911f7d9cfe162a26c83ed98/packages/backend/server/src/core/doc/writer.ts#L198-L234","documentation":"Plain Error thrown by updateDocMeta when called with meta.title === undefined. The method's only supported field is title, so an input without it is a no-op at best and almost always a caller bug. It is a generic Error (not BadRequest), so it will surface as 500 unless wrapped — a defect worth fixing in the library.","triggerScenarios":"Caller passes `{}` or omits title, e.g. `updateDocMeta(ws, doc, {})` or `updateDocMeta(ws, doc, { someOtherField: x })`. Often a frontend that builds the meta object conditionally and ends up with no keys.","commonSituations":"Frontend form where the title field was unchanged and the build-meta helper skipped it. A refactor that renamed the field but left old callers. Batch job iterating over objects that happen to have no title key.","solutions":["On the caller, only invoke updateDocMeta when meta.title !== undefined; skip the call entirely otherwise.","If title is the only field, prefer a dedicated setTitle method or require title as a positional arg so the type system rejects `{}`.","In the library, replace `throw new Error('No metadata provided')` with `throw new BadRequest('No metadata provided')` so it returns 400, not 500."],"exampleFix":"// before\nasync updateDocMeta(workspaceId, docId, meta: { title?: string }, editorId?) {\n  if (meta.title === undefined) {\n    throw new Error('No metadata provided');\n  }\n  ...\n}\n\n// after — make the contract explicit and return 400\nasync updateDocMeta(workspaceId, docId, title: string, editorId?) {\n  if (typeof title !== 'string' || title.length === 0) {\n    throw new BadRequest('title is required for updateDocMeta');\n  }\n  ...\n}","handlingStrategy":"validation","validationCode":"function buildMetaUpdate(input: { title?: string }) {\n  if (input.title === undefined) return null; // nothing to do — skip the call\n  return { title: input.title };\n}\n\nconst meta = buildMetaUpdate(form);\nif (meta) await writer.updateDocMeta(ws, doc, meta);","typeGuard":"function hasMetaTitle(meta: unknown): meta is { title: string } {\n  return typeof (meta as any)?.title === 'string';\n}","tryCatchPattern":"if (hasMetaTitle(form)) {\n  await writer.updateDocMeta(ws, doc, { title: form.title });\n} // else skip — never trigger the error","preventionTips":["Skip the call entirely when title is undefined instead of relying on the throw.","Prefer a positional `title: string` parameter to make the contract unambiguous.","In the library, upgrade the throw to BadRequest so it returns 400."],"tags":["doc","metadata","validation","input-validation"],"backgroundTag":null,"analyzedSha":"26c515e050211269e911f7d9cfe162a26c83ed98","analyzedAt":"2026-08-12T13:15:16.447Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}