{"record":{"id":"e937e9d08f8f7538","repo":"vercel/ai","slug":"acp-credentialenv-and-credentialbrokering-must-be-e937e9","errorCode":null,"errorMessage":"ACP credentialEnv and credentialBrokering must be configured together.","messagePattern":"ACP credentialEnv and credentialBrokering must be configured together\\.","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/harness-acp/src/v1/acp-v1-harness.ts","lineNumber":142,"sourceCode":"  startupTimeoutMs,\n  clientApp,\n  lifecycleStateSchema,\n}: {\n  settings: ACPV1Settings;\n  builtinTools: TBuiltinTools;\n  port?: number;\n  portEndpoint?: HarnessV1PortEndpoint;\n  startupTimeoutMs?: number;\n  clientApp: ACPClientApp;\n  lifecycleStateSchema: NonNullable<\n    HarnessV1<TBuiltinTools>['lifecycleStateSchema']\n  >;\n}): HarnessV1<TBuiltinTools> {\n  if (\n    (settings.credentialEnv == null) !==\n    (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    );","sourceCodeStart":124,"sourceCodeEnd":160,"githubUrl":"https://github.com/vercel/ai/blob/69428b1f8b037e4d118fb4853428d5c4e620493c/packages/harness-acp/src/v1/acp-v1-harness.ts#L124-L160","documentation":"createACPV1, the v1 implementation behind createACP, performs the same pair-validation as the outer factory: credentialEnv and credentialBrokering must both be present or both absent. The check exists in both layers so direct callers of the v1 path cannot bypass the invariant; providing only one makes credential injection ambiguous and is rejected.","triggerScenarios":"Reaching the v1 harness creation (via createACP or wrappers) with settings where exactly one of credentialEnv / credentialBrokering is set (including one being explicitly undefined while the other is provided).","commonSituations":"Programmatically constructing settings where one field is conditionally spread and the other is not; partial refactors; wrappers that fill in only one of the pair.","solutions":["Supply both credentialEnv and credentialBrokering together.","Omit both if credential brokering is not needed.","Ensure conditional settings construction keeps the fields consistent (spread both or neither)."],"exampleFix":"// before\ncreateACP({ credentialBrokering: { mode: 'sandbox' } }); // throws\n// after\ncreateACP({\n  credentialEnv: { DB_URL: '...' },\n  credentialBrokering: { mode: 'sandbox' },\n});","handlingStrategy":"validation","validationCode":"function validateCredentialPair(settings: { credentialEnv?: unknown; credentialBrokering?: unknown }): void {\n  if ((settings.credentialEnv == null) !== (settings.credentialBrokering == null)) {\n    throw new Error('credentialEnv and credentialBrokering must be set together.');\n  }\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Construct credential settings from one source object and spread both fields together.","Add schema/type-level coupling (single options object) to keep the pair aligned.","Test settings construction with both present and both absent cases."],"tags":["configuration","validation","acp"],"backgroundTag":"invalid-configuration","analyzedSha":"69428b1f8b037e4d118fb4853428d5c4e620493c","analyzedAt":"2026-08-30T12:32:21.016Z","schemaVersion":2},"datasetVersion":"2026-08-30T13:17:10.514Z"}