{"record":{"id":"9877b36c9e9a98c6","repo":"openclaw/openclaw","slug":"clickclack-setup-code-claim-returned-invalid-v1-co","errorCode":null,"errorMessage":"ClickClack setup code claim returned invalid v1 contract metadata","messagePattern":"ClickClack setup code claim returned invalid v1 contract metadata","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"extensions/clickclack/src/setup-claim.ts","lineNumber":83,"sourceCode":"  if (\n    allowFrom !== undefined &&\n    (!Array.isArray(allowFrom) || !allowFrom.every((entry) => typeof entry === \"string\"))\n  ) {\n    throw new Error(\"ClickClack setup code claim returned invalid defaults.allowFrom\");\n  }\n  if (agentActivity !== undefined && typeof agentActivity !== \"boolean\") {\n    throw new Error(\"ClickClack setup code claim returned invalid defaults.agentActivity\");\n  }\n  const contractVersion = claim.contract_version;\n  const apiBaseUrlValue = claim.api_base_url;\n  const hasContractMetadata = contractVersion !== undefined || apiBaseUrlValue !== undefined;\n  if (expectedClaimUrl && !hasContractMetadata) {\n    throw new Error(\"ClickClack setup code claim returned a legacy response for an exact endpoint\");\n  }\n  let contract: Pick<ClickClackSetupCodeClaim, \"contract_version\" | \"api_base_url\"> = {};\n  if (hasContractMetadata) {\n    if (contractVersion !== 1 || typeof apiBaseUrlValue !== \"string\") {\n      throw new Error(\"ClickClack setup code claim returned invalid v1 contract metadata\");\n    }\n    const apiBaseUrl = requireClickClackSetupApiBaseUrl(\n      apiBaseUrlValue,\n      \"setup code claim response.api_base_url\",\n    );\n    const canonicalClaimUrl = buildClickClackSetupClaimUrl(apiBaseUrl);\n    if (expectedClaimUrl && expectedClaimUrl !== canonicalClaimUrl) {\n      throw new Error(\n        \"ClickClack setup code claim returned an API base that does not match the claim URL\",\n      );\n    }\n    contract = { contract_version: 1, api_base_url: apiBaseUrl };\n  }\n  return {\n    ...contract,\n    token: requireString(claim, \"token\", \"response\"),\n    bot: {\n      id: requireString(bot, \"id\", \"bot\"),","sourceCodeStart":65,"sourceCodeEnd":101,"githubUrl":"https://github.com/openclaw/openclaw/blob/01804a75319da4b69c9ab98ceaa30477e22b8c0b/extensions/clickclack/src/setup-claim.ts#L65-L101","documentation":"The setup-code claim endpoint returned a JSON body that advertised v1 contract metadata (it included either a `contract_version` field, an `api_base_url` field, or both), but the values were malformed: `contract_version` was present and not exactly the number `1`, or `api_base_url` was present and not a string. This guard enforces the v1 wire contract so a half-upgraded or buggy server cannot push an incompatible/typo'd base URL into client config.","triggerScenarios":"Server response JSON contains `contract_version: 2` (or `0`, or `\"1\"` as a string), OR contains `api_base_url: null` / a number / an object, while at least one of the two fields is present. Triggered only when `hasContractMetadata` is true, i.e. either field is defined.","commonSituations":"ClickClack server was upgraded to a newer contract version the client does not speak yet; server bug returning `api_base_url` as `null` on error paths; a proxy/CDN injected a stub JSON body; client and server version skew after a partial deployment.","solutions":["Check the server response body/logs: confirm `contract_version` is exactly `1` (number) and `api_base_url` is a non-empty string.","Upgrade or downgrade the ClickClack server to match the client's supported v1 contract, or upgrade the openclaw/clickclack plugin to a version that speaks the server's contract.","If running a custom/mock claim endpoint, return `{\"contract_version\": 1, \"api_base_url\": \"https://your-host\", ...}` exactly.","File a bug against the server if a real production endpoint returns anything else — the client is correctly refusing an ambiguous response."],"exampleFix":"// Server (claim endpoint) — before\nreturn res.json({ contract_version: \"1\", api_base_url });\n// after\nreturn res.json({ contract_version: 1, api_base_url }); // numeric 1, string url","handlingStrategy":"try-catch","validationCode":"// Cannot fully validate a server response client-side; you can pre-check the server is reachable.\n// Pre-flight: GET the claim endpoint's OpenAPI/health if available, or assert the server version matches v1 contract via admin API before invoking setup.","typeGuard":"// Validates a raw server payload *before* handing it to the parser.\nfunction isV1ContractPayload(v: unknown): v is { contract_version: 1; api_base_url: string } {\n  return (\n    !!v && typeof v === 'object' &&\n    (v as any).contract_version === 1 &&\n    typeof (v as any).api_base_url === 'string'\n  );\n}","tryCatchPattern":"try {\n  const claim = await claimClickClackSetupCode(params);\n} catch (e) {\n  if (e instanceof Error && /invalid v1 contract metadata/.test(e.message)) {\n    // server spoke a different contract — surface upgrade guidance, do not retry blindly\n    throw new Error('ClickClack server returned an unsupported contract version. Upgrade the plugin or the server.');\n  }\n  throw e;\n}","preventionTips":["Pin client and server to matching released versions.","Monitor server-side logs for `contract_version`/`api_base_url` shape regressions.","For mock servers, return exactly `{contract_version: 1, api_base_url: '<string>'}`."],"tags":["setup","contract","validation","server-response","clickclack"],"backgroundTag":null,"analyzedSha":"01804a75319da4b69c9ab98ceaa30477e22b8c0b","analyzedAt":"2026-08-12T04:37:58.197Z","schemaVersion":2},"datasetVersion":"2026-08-13T04:17:16.726Z"}