toeverything/AFFiNE · error · BadRequestException

description must be provided explicitly.

Error message

description must be provided explicitly.

What it means

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.

Source

Thrown at packages/backend/server/src/plugins/copilot/byok/resolver.ts:723

      .user(userId)
      .workspace(workspaceId)
      .allowLocal()
      .assert('Workspace.Settings.Read');
  }

  private async assertUpdate(userId: string, workspaceId: string) {
    await this.ac
      .user(userId)
      .workspace(workspaceId)
      .allowLocal()
      .assert('Workspace.Settings.Update');
    await this.entitlement.assertManagementAccess(workspaceId, userId);
  }
}

function requireExplicitDescription(input: { description: string | null }) {
  if (!Object.hasOwn(input, 'description')) {
    throw new BadRequestException('description must be provided explicitly.');
  }
}

function nativeDefinition(input: WorkspaceByokProfileDefinitionInput) {
  return {
    ...input,
    endpoint: {
      ...input.endpoint,
      url: input.endpoint.url ?? undefined,
      dialect: input.endpoint.dialect ?? undefined,
    },
  };
}

function projectProbe(probe: {
  kind: string;
  testedAtMs?: number;
  errorKind?: string;

View on GitHub (pinned to b4c8548c09)

Solutions

  1. Always include description in the update input — pass its current value to keep it, or null to clear it.
  2. 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.
  3. On the server, consider splitting into explicit update paths if clients cannot express 'field absent' vs 'field null'.

Example fix

# before
mutation { updateByokProfile(workspaceId: "ws", input: { name: "gpt4" }) }

# after — description present; null clears it explicitly
mutation { updateByokProfile(workspaceId: "ws", input: { name: "gpt4", description: null }) }
Defensive patterns

Strategy: validation

Validate before calling

// Explicitly control field presence before sending the update
const input: WorkspaceByokProfileDefinitionInput & { description: string | null } = {
  ...patch,
  description: 'description' in patch ? patch.description : currentProfile.description,
};

Type guard

const hasExplicitDescription = (
  input: object
): input is { description: string | null } =>
  Object.hasOwn(input, 'description');

Try / catch

try {
  await updateByokProfile({ workspaceId, input });
} catch (e) {
  if (/description must be provided explicitly/i.test(String(e?.message))) {
    return updateByokProfile({ workspaceId, input: { ...input, description: input.description ?? null } });
  }
  throw e;
}

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Understand the failure class

Background: "Missing required field" and "field is required" errors: why libraries reject payloads that omit mandatory fields — this error's family across 20 libraries.

Related errors


AI-assisted analysis of toeverything/AFFiNE@b4c8548c09 (2026-08-18). Data as JSON: /api/errors/068e1891069d1028. Report an issue: GitHub.