{"record":{"id":"068e1891069d1028","repo":"toeverything/AFFiNE","slug":"description-must-be-provided-explicitly","errorCode":null,"errorMessage":"description must be provided explicitly.","messagePattern":"description must be provided explicitly\\.","errorType":"exception","errorClass":"BadRequestException","httpStatus":400,"severity":"error","filePath":"packages/backend/server/src/plugins/copilot/byok/resolver.ts","lineNumber":723,"sourceCode":"      .user(userId)\n      .workspace(workspaceId)\n      .allowLocal()\n      .assert('Workspace.Settings.Read');\n  }\n\n  private async assertUpdate(userId: string, workspaceId: string) {\n    await this.ac\n      .user(userId)\n      .workspace(workspaceId)\n      .allowLocal()\n      .assert('Workspace.Settings.Update');\n    await this.entitlement.assertManagementAccess(workspaceId, userId);\n  }\n}\n\nfunction requireExplicitDescription(input: { description: string | null }) {\n  if (!Object.hasOwn(input, 'description')) {\n    throw new BadRequestException('description must be provided explicitly.');\n  }\n}\n\nfunction nativeDefinition(input: WorkspaceByokProfileDefinitionInput) {\n  return {\n    ...input,\n    endpoint: {\n      ...input.endpoint,\n      url: input.endpoint.url ?? undefined,\n      dialect: input.endpoint.dialect ?? undefined,\n    },\n  };\n}\n\nfunction projectProbe(probe: {\n  kind: string;\n  testedAtMs?: number;\n  errorKind?: string;","sourceCodeStart":705,"sourceCodeEnd":741,"githubUrl":"https://github.com/toeverything/AFFiNE/blob/b4c8548c09da21b2898443559a5b846f0ccf5dd8/packages/backend/server/src/plugins/copilot/byok/resolver.ts#L705-L741","documentation":"Input contract check in the BYOK resolver: updating a workspace BYOK profile requires the description field to be present in the mutation input — explicitly, even when the intent is to clear it (description: null). requireExplicitDescription uses Object.hasOwn(input, 'description'), so omitting the key entirely (as many GraphQL clients do for unchanged fields) throws BadRequestException instead of silently leaving description untouched.","triggerScenarios":"Calling updateByokProfile (or equivalent) with the description field omitted; GraphQL clients that strip null/unset fields before sending; code paths building the input via spread of a partial object where description was never set; auto-generated clients dropping optional fields.","commonSituations":"Frontend forms that only send changed fields; Apollo/urql normalized updates pruning nulls; scripts PATCHing only the fields they modify; client generated from schema marking description optional and omitting it.","solutions":["Always include description in the update input — pass its current value to keep it, or null to clear it.","If your GraphQL client prunes nulls, configure it to preserve explicit nulls for this mutation (e.g. omitNull: false in apollo-client v3 composites) or build the input literal manually.","On the server, consider splitting into explicit update paths if clients cannot express 'field absent' vs 'field null'."],"exampleFix":"# before\nmutation { updateByokProfile(workspaceId: \"ws\", input: { name: \"gpt4\" }) }\n\n# after — description present; null clears it explicitly\nmutation { updateByokProfile(workspaceId: \"ws\", input: { name: \"gpt4\", description: null }) }","handlingStrategy":"validation","validationCode":"// Explicitly control field presence before sending the update\nconst input: WorkspaceByokProfileDefinitionInput & { description: string | null } = {\n  ...patch,\n  description: 'description' in patch ? patch.description : currentProfile.description,\n};","typeGuard":"const hasExplicitDescription = (\n  input: object\n): input is { description: string | null } =>\n  Object.hasOwn(input, 'description');","tryCatchPattern":"try {\n  await updateByokProfile({ workspaceId, input });\n} catch (e) {\n  if (/description must be provided explicitly/i.test(String(e?.message))) {\n    return updateByokProfile({ workspaceId, input: { ...input, description: input.description ?? null } });\n  }\n  throw e;\n}","preventionTips":["Always include description in update inputs — current value to keep, null to clear.","Configure the GraphQL client to preserve explicit nulls instead of pruning them.","Write a client-side hasExplicitDescription check before submitting BYOK updates."],"tags":["byok","graphql","input-validation","optional-fields","null-semantics"],"backgroundTag":"missing-required-field","analyzedSha":"b4c8548c09da21b2898443559a5b846f0ccf5dd8","analyzedAt":"2026-08-18T21:16:52.546Z","schemaVersion":2},"datasetVersion":"2026-08-21T13:17:26.733Z"}