vercel/ai · error · Error

ACP harnessId must be a stable kebab-case identifier; receiv

Error message

ACP harnessId must be a stable kebab-case identifier; received ${JSON.stringify(settings.harnessId)}.

What it means

createACPV1 validates settings.harnessId against HARNESS_ID_REGEXP, which requires a stable kebab-case identifier. The harnessId is used in logs, state files, bridge directories, and error messages, so an unstable or oddly formatted id (spaces, camelCase, symbols, empty) is rejected with a message echoing the received value.

Source

Thrown at packages/harness-acp/src/v1/acp-v1-harness.ts:158

    (settings.credentialBrokering == null)
  ) {
    throw new Error(
      'ACP credentialEnv and credentialBrokering must be configured together.',
    );
  }
  if (
    settings.mcpServers != null &&
    Object.prototype.hasOwnProperty.call(
      settings.mcpServers,
      'ai-sdk-harness-tools',
    )
  ) {
    throw new Error(
      'ACP MCP server name "ai-sdk-harness-tools" is reserved for HarnessAgent tools.',
    );
  }
  if (!HARNESS_ID_REGEXP.test(settings.harnessId)) {
    throw new Error(
      `ACP harnessId must be a stable kebab-case identifier; received ${JSON.stringify(settings.harnessId)}.`,
    );
  }
  const implementation = createACPV1Implementation({ settings });
  validateACPV1Implementation(implementation);
  const bootstrap = createACPBootstrap({
    harnessId: settings.harnessId,
    implementation,
  });
  const permissionModeMapping = isCompletePermissionModeMapping({
    value: settings.permissionModeMapping,
  })
    ? settings.permissionModeMapping
    : undefined;

  return {
    specificationVersion: 'harness-v1',
    harnessId: settings.harnessId,

View on GitHub (pinned to 69428b1f8b)

Solutions

  1. Convert the id to lowercase kebab-case, e.g. 'my-agent-harness'.
  2. Make the id stable across runs (do not include timestamps or random suffixes) so lifecycle state can be resumed.
  3. Check HARNESS_ID_REGEXP in acp-v1-harness.ts and match its pattern exactly.

Example fix

// before
createACP({ harnessId: 'My Coding Agent' }); // throws
// after
createACP({ harnessId: 'my-coding-agent' });
Defensive patterns

Strategy: validation

Validate before calling

const HARNESS_ID_REGEXP = /^[a-z0-9]+(-[a-z0-9]+)*$/;
function isValidHarnessId(id: string): boolean {
  return HARNESS_ID_REGEXP.test(id);
}
if (!isValidHarnessId(myHarnessId)) throw new Error(`harnessId must be kebab-case: ${myHarnessId}`);

Type guard

function isKebabCaseId(v: unknown): v is string {
  return typeof v === 'string' && /^[a-z0-9]+(-[a-z0-9]+)*$/.test(v);
}

Prevention

When it happens

Trigger: Calling createACP/createACPV1 with a harnessId such as 'My Harness', 'myHarness', 'my_harness', '', or one containing invalid characters that fail HARNESS_ID_REGEXP.

Common situations: Deriving harnessId from a display name or package name without normalizing to kebab-case; building ids dynamically per-run (defeating the 'stable' requirement for resume/state lookup); copy-paste with mixed casing.

Related errors


AI-assisted analysis of vercel/ai@69428b1f8b (2026-08-30). Data as JSON: /api/errors/e648f3c54334472c. Report an issue: GitHub.