paperclipai/paperclip · warning · RunnerGoalActionError
goal_token_budget_unsupported
goal_token_budget_unsupported
Error message
goal_token_budget_unsupported: This agent session does not support goal token budgets.
What it means
`act` rejects goal actions carrying a `tokenBudget` when the session's capability lacks `tokenBudgetControl`, throwing code `goal_token_budget_unsupported`. Goal-level token budgets are an optional adapter capability; requesting one on a session that can't enforce it is a hard error.
Source
Thrown at server/src/services/runner-goals.ts:431
if (session.goalRevision !== request.expectedRevision) {
throw new RunnerGoalConflictError("stale_revision", currentProjection);
}
const capability = storedCapability(session, fallbackCapability);
const requiredCapabilityAction = request.action === "pause"
? "pause"
: request.action === "resume"
? "resume"
: request.action === "clear"
? "clear"
: "set";
if (capability.availability !== "available" || !capability.actions.includes(requiredCapabilityAction)) {
throw new RunnerGoalActionError(
capability.reasonCode ?? "goal_action_unsupported",
capability.reason ?? `${request.action} is unsupported by this agent session.`,
);
}
if (request.tokenBudget != null && !capability.tokenBudgetControl) {
throw new RunnerGoalActionError(
"goal_token_budget_unsupported",
"This agent session does not support goal token budgets.",
);
}
if (request.action === "create" && currentGoal && currentGoal.status !== "complete") {
throw new RunnerGoalConflictError("replacement_required", currentProjection);
}
if (["edit", "replace", "pause", "resume", "clear"].includes(request.action) && !currentGoal) {
throw new RunnerGoalActionError("goal_not_found", "There is no current session goal.");
}
const nextRevision = session.goalRevision + 1;
const desiredState = request.action === "pause"
? "paused"
: request.action === "clear"
? null
: "active";
await tx.update(agentTaskSessions).set({View on GitHub (pinned to 01ad858492)
Solutions
- Omit `tokenBudget` from the request when `capability.tokenBudgetControl` is falsy
- Check the projection before sending: `if (proj.capability.tokenBudgetControl)` gate the field
- Enforce budgets out-of-band (board-level budget auto-pause) for adapters without goal budget support
- Upgrade to an adapter that supports token budget control if budgets are required
Example fix
// before
await act(companyId, issueId, { agentId, action: 'set', goal, tokenBudget: 5000 });
// after
const proj = await projection(companyId, issueId, agentId);
await act(companyId, issueId, { agentId, action: 'set', goal,
...(proj.capability.tokenBudgetControl ? { tokenBudget: 5000 } : {}) }); Defensive patterns
Strategy: validation
Validate before calling
const proj = await runnerGoals.projection(companyId, issueId, agentId);
if (tokenBudget != null && !proj.capability.tokenBudgetControl) {
delete req.tokenBudget; // or reject at the call site
} Type guard
function supportsTokenBudget(proj) {
return proj?.capability?.tokenBudgetControl === true;
} Try / catch
try {
await runnerGoals.act(companyId, issueId, req);
} catch (e) {
if (e instanceof RunnerGoalActionError && e.code === 'goal_token_budget_unsupported') {
const { tokenBudget, ...rest } = req;
return await runnerGoals.act(companyId, issueId, rest); // retry without budget
}
throw e;
} Prevention
- Conditionally include tokenBudget only when capability.tokenBudgetControl is true
- Never blanket-forward tokenBudget from generic tooling
- Offer budget UI only for budget-capable adapters
- Use board-level budget controls as the fallback
When it happens
Trigger: Including `tokenBudget` in RunnerGoalActionRequest for an agent/adapter that does not advertise `capability.tokenBudgetControl`; blindly forwarding a tokenBudget field from generic goal tooling.
Common situations: Generic goal-management UI always sends tokenBudget; migrating workflows between adapters with differing budget support; adapter capability probe didn't detect budget control so the field is unsupported.
Understand the failure class
Background: UnsupportedOperationException and "is not supported" errors: when a library deliberately refuses a call — this error's family across 30 libraries.
Related errors
- session_goals_unsupported
- goal_action_unsupported
- ${prefix}: the capability must be an object.
- DUPLEX_CHANNEL_CAPABILITY_DENIED
- OpenCode interruption is unavailable
AI-assisted analysis of paperclipai/paperclip@01ad858492 (2026-09-10).
Data as JSON: /api/errors/35a4fe6e5b1ffdea.
Report an issue: GitHub.