can1357/oh-my-pi · error · Error
goal token_budget must be a positive integer when provided
Error message
goal token_budget must be a positive integer when provided
What it means
validateTokenBudget guards the optional tokenBudget argument passed to goal create/replace operations. It throws when the value is provided but is not a positive whole number (non-integer, zero, or negative), because a budget must represent a countable, spendable token allowance.
Source
Thrown at packages/coding-agent/src/goals/runtime.ts:109
timeUsedSeconds: String(goal.timeUsedSeconds),
});
}
export function completionBudgetReport(goal: Goal): string | null {
const parts: string[] = [];
if (goal.tokenBudget !== undefined) {
parts.push(`tokens used: ${goal.tokensUsed} of ${goal.tokenBudget}`);
}
if (goal.timeUsedSeconds > 0) {
parts.push(`time used: ${goal.timeUsedSeconds} seconds`);
}
if (parts.length === 0) return null;
return `Goal achieved. Report final budget usage to the user: ${parts.join("; ")}.`;
}
function validateTokenBudget(tokenBudget: number | undefined): void {
if (tokenBudget !== undefined && (!Number.isInteger(tokenBudget) || tokenBudget <= 0)) {
throw new Error("goal token_budget must be a positive integer when provided");
}
}
function isAccountingStatus(goal: Goal): boolean {
return goal.status === "active" || goal.status === "budget-limited";
}
export class GoalRuntime {
readonly #host: GoalRuntimeHost;
#turnSnapshot: GoalTurnSnapshot | undefined;
#wallClock: GoalWallClockSnapshot;
#budgetReportedFor: string | undefined;
#accountingTail: Promise<void> = Promise.resolve();
constructor(host: GoalRuntimeHost) {
this.#host = host;
this.#wallClock = { lastAccountedAt: this.#now() };
}View on GitHub (pinned to 9690622007)
Solutions
- Omit tokenBudget entirely (undefined) if no budget is wanted instead of passing 0
- Round or validate the value: only pass positive integers
- Convert string input with Number.parseInt/Number() and check Number.isInteger before calling
- Fix config/CLI parsing so token_budget is deserialized as a number
Example fix
// before
await goals.createGoal({ objective: 'ship v2', tokenBudget: 0 });
// after
const budget = Number(process.env.GOAL_TOKEN_BUDGET);
await goals.createGoal({
objective: 'ship v2',
tokenBudget: Number.isInteger(budget) && budget > 0 ? budget : undefined,
}); Defensive patterns
Strategy: validation
Validate before calling
function isValidTokenBudget(v: unknown): v is number {
return typeof v === 'number' && Number.isInteger(v) && v > 0;
}
// call site: const tokenBudget = isValidTokenBudget(raw) ? raw : undefined; Type guard
function isValidTokenBudget(v: unknown): v is number {
return typeof v === 'number' && Number.isInteger(v) && v > 0;
} Try / catch
try {
await runtime.createGoal({ objective, tokenBudget });
} catch (err) {
if (err instanceof Error && err.message.includes('token_budget must be a positive integer')) {
tokenBudget = undefined; // retry without budget
} else throw err;
} Prevention
- Use undefined (not 0) as the 'no budget' sentinel
- Coerce and validate numeric config values at the boundary (Number.isInteger, > 0)
- Type the input as number | undefined so strings/floats fail at compile time
When it happens
Trigger: Calling createGoal or replaceGoal with tokenBudget set to 0, a negative number, a float (e.g. 1000.5), NaN, or a non-number value that slipped past typing; validateTokenBudget is also invoked via onBudgetMutated.
Common situations: Parsing token_budget from CLI args or JSON config where the value arrives as a string or float; computing a budget from a formula that yields a fractional value; defaulting to 0 as a sentinel for 'unset' instead of undefined.
Understand the failure class
Background: "must be positive", "Invalid value": how libraries reject invalid parameter values (ValueError, ArgumentError, INVALID_PARAMETER_VALUE) — this error's family across 28 libraries.
Related errors
- objective is required when op=create
- objective is required when op=replace
- Expected --${name} to be a positive integer, got ${value}
- Cache flags require --cache
- --alias requires --profile <name> or OMP_PROFILE
AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31).
Data as JSON: /api/errors/e125f95eccb857c9.
Report an issue: GitHub.