{"record":{"id":"b2a6e557d76cafd8","repo":"paperclipai/paperclip","slug":"the-negotiated-acp-goal-extension-does-not-support","errorCode":null,"errorMessage":"The negotiated ACP goal extension does not support token budget control","messagePattern":"The negotiated ACP goal extension does not support token budget control","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"packages/paperclip-runner/src/cli/acpx-runtime-sidecar.ts","lineNumber":453,"sourceCode":"      ),\n      status: sanitizeRuntimeStatus(\n        await readSidecarHostStatusWithin(activeHost),\n      ),\n      runId,\n      turnId,\n      sequence,\n      pendingToolCount: tools.size,\n      pendingInputCount: inputs.size,\n    };\n  }\n  if (request.command === \"session.goal.get\") {\n    const activeHost = requireHost();\n    return observedGoalProjection(activeHost.goalCapability(), activeHost.goalSnapshot(), turnId !== null);\n  }\n  if (request.command === \"session.goal.set\") {\n    const activeHost = requireHost();\n    if (Object.prototype.hasOwnProperty.call(request.params, \"tokenBudget\")) {\n      throw new Error(\"The negotiated ACP goal extension does not support token budget control\");\n    }\n    const objective = text(request.params.objective).trim();\n    const status = text(request.params.status).trim();\n    const action = objective\n      ? \"set\"\n      : status === \"paused\"\n        ? \"pause\"\n        : status === \"active\"\n          ? \"resume\"\n          : null;\n    if (!action) throw new Error(\"session.goal.set requires an objective or active/paused status\");\n    const goal = await activeHost.controlGoal(action, objective || undefined);\n    return observedGoalProjection(activeHost.goalCapability(), goal, turnId !== null);\n  }\n  if (request.command === \"session.goal.clear\") {\n    const activeHost = requireHost();\n    await activeHost.controlGoal(\"clear\");\n    return observedGoalProjection(activeHost.goalCapability(), null, turnId !== null);","sourceCodeStart":435,"sourceCodeEnd":471,"githubUrl":"https://github.com/paperclipai/paperclip/blob/01ad8584922b5d85292b1723cae71fa0d9b07a19/packages/paperclip-runner/src/cli/acpx-runtime-sidecar.ts#L435-L471","documentation":"The ACP goal extension negotiated with the runtime only supports objective/status management, not per-session token budget control. When a client sends the session.goal.set command with a tokenBudget field, the sidecar rejects it outright because the capability is unavailable in this negotiation, rather than silently ignoring the budget.","triggerScenarios":"Sending a dispatch request with command 'session.goal.set' whose params object contains a 'tokenBudget' property (checked via hasOwnProperty, so even null/undefined values trigger it).","commonSituations":"A caller upgraded from a runtime build that supported token budgets, or a client library always includes tokenBudget in goal-set params; generic orchestration code reusing one params shape across goal operations.","solutions":["Remove the tokenBudget property from the session.goal.set params","Gate token budget handling behind the negotiated goal capability before sending the command","Update to a runtime build whose ACP goal extension supports token budget control"],"exampleFix":"// before\nhost.dispatch({ command: 'session.goal.set', params: { objective: 'ship', tokenBudget: 5000 } });\n// after\nhost.dispatch({ command: 'session.goal.set', params: { objective: 'ship' } });","handlingStrategy":"validation","validationCode":"function canSetGoalWithBudget(params) { return params && !('tokenBudget' in params); }\nif (!canSetGoalWithBudget(params)) delete params.tokenBudget;","typeGuard":"function isBudgetFreeGoalParams(p: unknown): p is { objective?: string; status?: string } {\n  return typeof p === 'object' && p !== null && !('tokenBudget' in p);\n}","tryCatchPattern":"try { await host.dispatch({ command: 'session.goal.set', params }); }\ncatch (e) { if (String(e.message).includes('token budget control')) { const { tokenBudget, ...rest } = params; await host.dispatch({ command: 'session.goal.set', params: rest }); } else throw e; }","preventionTips":["Never include tokenBudget in goal.set params unless capability negotiation advertised it","Check the negotiated goal capability before sending extension fields","Strip unknown/extension fields from command params before dispatch"],"tags":["acp","capability-negotiation","unsupported-feature"],"backgroundTag":"unsupported-operation","analyzedSha":"01ad8584922b5d85292b1723cae71fa0d9b07a19","analyzedAt":"2026-09-10T03:14:50.855Z","contentChangedAt":"2026-09-10T03:14:50.855Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}