openclaw/openclaw · error · Error

ClickClack setup code claim returned invalid v1 contract met

Error message

ClickClack setup code claim returned invalid v1 contract metadata

What it means

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.

Source

Thrown at extensions/clickclack/src/setup-claim.ts:83

  if (
    allowFrom !== undefined &&
    (!Array.isArray(allowFrom) || !allowFrom.every((entry) => typeof entry === "string"))
  ) {
    throw new Error("ClickClack setup code claim returned invalid defaults.allowFrom");
  }
  if (agentActivity !== undefined && typeof agentActivity !== "boolean") {
    throw new Error("ClickClack setup code claim returned invalid defaults.agentActivity");
  }
  const contractVersion = claim.contract_version;
  const apiBaseUrlValue = claim.api_base_url;
  const hasContractMetadata = contractVersion !== undefined || apiBaseUrlValue !== undefined;
  if (expectedClaimUrl && !hasContractMetadata) {
    throw new Error("ClickClack setup code claim returned a legacy response for an exact endpoint");
  }
  let contract: Pick<ClickClackSetupCodeClaim, "contract_version" | "api_base_url"> = {};
  if (hasContractMetadata) {
    if (contractVersion !== 1 || typeof apiBaseUrlValue !== "string") {
      throw new Error("ClickClack setup code claim returned invalid v1 contract metadata");
    }
    const apiBaseUrl = requireClickClackSetupApiBaseUrl(
      apiBaseUrlValue,
      "setup code claim response.api_base_url",
    );
    const canonicalClaimUrl = buildClickClackSetupClaimUrl(apiBaseUrl);
    if (expectedClaimUrl && expectedClaimUrl !== canonicalClaimUrl) {
      throw new Error(
        "ClickClack setup code claim returned an API base that does not match the claim URL",
      );
    }
    contract = { contract_version: 1, api_base_url: apiBaseUrl };
  }
  return {
    ...contract,
    token: requireString(claim, "token", "response"),
    bot: {
      id: requireString(bot, "id", "bot"),

View on GitHub (pinned to 01804a7531)

Solutions

  1. Check the server response body/logs: confirm `contract_version` is exactly `1` (number) and `api_base_url` is a non-empty string.
  2. 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.
  3. If running a custom/mock claim endpoint, return `{"contract_version": 1, "api_base_url": "https://your-host", ...}` exactly.
  4. File a bug against the server if a real production endpoint returns anything else — the client is correctly refusing an ambiguous response.

Example fix

// Server (claim endpoint) — before
return res.json({ contract_version: "1", api_base_url });
// after
return res.json({ contract_version: 1, api_base_url }); // numeric 1, string url
Defensive patterns

Strategy: try-catch

Validate before calling

// Cannot fully validate a server response client-side; you can pre-check the server is reachable.
// 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.

Type guard

// Validates a raw server payload *before* handing it to the parser.
function isV1ContractPayload(v: unknown): v is { contract_version: 1; api_base_url: string } {
  return (
    !!v && typeof v === 'object' &&
    (v as any).contract_version === 1 &&
    typeof (v as any).api_base_url === 'string'
  );
}

Try / catch

try {
  const claim = await claimClickClackSetupCode(params);
} catch (e) {
  if (e instanceof Error && /invalid v1 contract metadata/.test(e.message)) {
    // server spoke a different contract — surface upgrade guidance, do not retry blindly
    throw new Error('ClickClack server returned an unsupported contract version. Upgrade the plugin or the server.');
  }
  throw e;
}

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Related errors


AI-assisted analysis of openclaw/openclaw@01804a7531 (2026-08-12). Data as JSON: /api/errors/9877b36c9e9a98c6. Report an issue: GitHub.