{"record":{"id":"e648f3c54334472c","repo":"vercel/ai","slug":"acp-harnessid-must-be-a-stable-kebab-case-identifi","errorCode":null,"errorMessage":"ACP harnessId must be a stable kebab-case identifier; received ${JSON.stringify(settings.harnessId)}.","messagePattern":"ACP harnessId must be a stable kebab-case identifier; received (.+?)\\.","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/harness-acp/src/v1/acp-v1-harness.ts","lineNumber":158,"sourceCode":"    (settings.credentialBrokering == null)\n  ) {\n    throw new Error(\n      'ACP credentialEnv and credentialBrokering must be configured together.',\n    );\n  }\n  if (\n    settings.mcpServers != null &&\n    Object.prototype.hasOwnProperty.call(\n      settings.mcpServers,\n      'ai-sdk-harness-tools',\n    )\n  ) {\n    throw new Error(\n      'ACP MCP server name \"ai-sdk-harness-tools\" is reserved for HarnessAgent tools.',\n    );\n  }\n  if (!HARNESS_ID_REGEXP.test(settings.harnessId)) {\n    throw new Error(\n      `ACP harnessId must be a stable kebab-case identifier; received ${JSON.stringify(settings.harnessId)}.`,\n    );\n  }\n  const implementation = createACPV1Implementation({ settings });\n  validateACPV1Implementation(implementation);\n  const bootstrap = createACPBootstrap({\n    harnessId: settings.harnessId,\n    implementation,\n  });\n  const permissionModeMapping = isCompletePermissionModeMapping({\n    value: settings.permissionModeMapping,\n  })\n    ? settings.permissionModeMapping\n    : undefined;\n\n  return {\n    specificationVersion: 'harness-v1',\n    harnessId: settings.harnessId,","sourceCodeStart":140,"sourceCodeEnd":176,"githubUrl":"https://github.com/vercel/ai/blob/69428b1f8b037e4d118fb4853428d5c4e620493c/packages/harness-acp/src/v1/acp-v1-harness.ts#L140-L176","documentation":"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.","triggerScenarios":"Calling createACP/createACPV1 with a harnessId such as 'My Harness', 'myHarness', 'my_harness', '', or one containing invalid characters that fail HARNESS_ID_REGEXP.","commonSituations":"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.","solutions":["Convert the id to lowercase kebab-case, e.g. 'my-agent-harness'.","Make the id stable across runs (do not include timestamps or random suffixes) so lifecycle state can be resumed.","Check HARNESS_ID_REGEXP in acp-v1-harness.ts and match its pattern exactly."],"exampleFix":"// before\ncreateACP({ harnessId: 'My Coding Agent' }); // throws\n// after\ncreateACP({ harnessId: 'my-coding-agent' });","handlingStrategy":"validation","validationCode":"const HARNESS_ID_REGEXP = /^[a-z0-9]+(-[a-z0-9]+)*$/;\nfunction isValidHarnessId(id: string): boolean {\n  return HARNESS_ID_REGEXP.test(id);\n}\nif (!isValidHarnessId(myHarnessId)) throw new Error(`harnessId must be kebab-case: ${myHarnessId}`);","typeGuard":"function isKebabCaseId(v: unknown): v is string {\n  return typeof v === 'string' && /^[a-z0-9]+(-[a-z0-9]+)*$/.test(v);\n}","tryCatchPattern":null,"preventionTips":["Normalize names with a toKebabCase helper before assigning harnessId.","Keep harnessId constant per logical agent — derive it from a config constant, not runtime data.","Validate ids where they are first defined (config module) rather than at harness creation."],"tags":["configuration","validation","naming"],"backgroundTag":"invalid-identifier-format","analyzedSha":"69428b1f8b037e4d118fb4853428d5c4e620493c","analyzedAt":"2026-08-30T12:32:21.016Z","schemaVersion":2},"datasetVersion":"2026-08-30T13:17:10.514Z"}