toeverything/AFFiNE · error · BadRequestException

MCP credential name is required

Error message

MCP credential name is required

What it means

BadRequestException('MCP credential name is required') thrown in issue() when the trimmed name is empty or longer than 64 characters. Rejected before creation, so no partial credential rows appear. Note the message only says 'required' even though >64 chars also triggers it — a client showing only the message will mislead users about over-length names.

Source

Thrown at packages/backend/server/src/plugins/copilot/mcp/credential.ts:200

      new Date(now.getTime() - LAST_USED_WRITE_INTERVAL_MS),
      now
    );
    return credential;
  }

  private async issue(
    input: IssueMcpCredential & {
      familyId?: string;
      generation?: number;
      graceEndsAt?: Date;
    }
  ) {
    if (!ALLOWED_EXPIRATION_DAYS.has(input.expirationDays)) {
      throw new BadRequestException('Unsupported MCP credential expiration');
    }
    const name = input.name.trim();
    if (!name || name.length > 64) {
      throw new BadRequestException('MCP credential name is required');
    }

    const id = randomUUID();
    const secret = this.crypto.randomBytes(32).toString('base64url');
    const secretHash = this.crypto.sha256(secret).toString('hex');
    const credential = await this.models.mcpCredential.create({
      id,
      familyId: input.familyId ?? id,
      generation: input.generation ?? 0,
      name,
      secretHash,
      fingerprint: secretHash.slice(0, 12),
      userId: input.userId,
      workspaceId: input.workspaceId,
      accessMode: input.accessMode,
      expiresAt: new Date(
        Date.now() + input.expirationDays * 24 * 60 * 60 * 1000
      ),

View on GitHub (pinned to b4c8548c09)

Solutions

  1. Trim the name client-side and enforce 1-64 characters before submitting
  2. Shorten auto-generated names (truncate the URL-derived suffix)
  3. As a maintainer: split the message into 'required' vs 'too long' for accurate client feedback

Example fix

// before
await credentials.create({ name: rawUrl, expirationDays: 90, ... });

// after
const name = rawUrl.trim().slice(0, 64) || 'mcp-credential';
if (!rawUrl.trim()) throw new UserError('Name is required');
await credentials.create({ name, expirationDays: 90, ... });
Defensive patterns

Strategy: validation

Validate before calling

const name = rawName.trim();
if (!name) throw new UserError('Credential name is required');
if (name.length > 64) throw new UserError('Credential name must be at most 64 characters');
await credentials.create({ ...input, name });

Type guard

const isValidCredentialName = (n: unknown): n is string =>
  typeof n === 'string' && n.trim().length >= 1 && n.trim().length <= 64;

Try / catch

try {
  await credentials.create(input);
} catch (e) {
  if (e instanceof BadRequestException && /name is required/.test(e.message)) {
    promptUserForName(); // covers both empty and >64 cases
  } else throw e;
}

Prevention

When it happens

Trigger: createMcpCredential with name of spaces/empty string; a 65+ character name (e.g. auto-generated from a long server URL); name that is only whitespace after trim.

Common situations: UI auto-names credentials from MCP server URLs which can exceed 64 chars; form validation missing on the client; user pastes a sentence as the name.

Related errors


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