can1357/oh-my-pi · error · Error

objective is required when op=create

Error message

objective is required when op=create

What it means

createGoal requires a non-empty objective string. The runtime trims the input and throws when the result is empty, since a goal with no objective is meaningless to track or report on.

Source

Thrown at packages/coding-agent/src/goals/runtime.ts:386

	#createGoalState(objective: string, tokenBudget: number | undefined): GoalModeState {
		const now = this.#now();
		const goal: Goal = {
			id: String(Snowflake.next()),
			objective,
			status: "active",
			tokenBudget,
			tokensUsed: 0,
			timeUsedSeconds: 0,
			createdAt: now,
			updatedAt: now,
		};
		return { enabled: true, mode: "active", goal };
	}

	async createGoal(input: { objective: string; tokenBudget?: number }): Promise<GoalModeState> {
		const objective = input.objective.trim();
		if (!objective) throw new Error("objective is required when op=create");
		validateTokenBudget(input.tokenBudget);
		return await this.#withAccounting(async () => {
			const existing = this.#host.getState();
			if (existing?.goal && existing.goal.status !== "dropped" && existing.goal.status !== "complete") {
				throw new Error("cannot create a new goal because this session already has a goal");
			}
			const state = this.#createGoalState(objective, input.tokenBudget);
			this.#budgetReportedFor = undefined;
			this.#markActiveAccounting(state.goal);
			await this.#commitState(state, { persist: "goal" });
			return state;
		});
	}

	async replaceGoal(input: { objective: string; tokenBudget?: number }): Promise<GoalModeState> {
		const objective = input.objective.trim();
		if (!objective) throw new Error("objective is required when op=replace");
		validateTokenBudget(input.tokenBudget);

View on GitHub (pinned to 9690622007)

Solutions

  1. Provide a meaningful objective string before calling createGoal
  2. Trim and check the objective in the caller and show a validation message instead
  3. Reject empty objective at the tool/schema boundary so the runtime is never called with one

Example fix

// before
await runtime.createGoal({ objective: userGoal.trim() });
// after
const objective = userGoal.trim();
if (!objective) throw new Error('Goal objective must not be empty');
await runtime.createGoal({ objective });
Defensive patterns

Strategy: validation

Validate before calling

if (typeof objective !== 'string' || objective.trim().length === 0) {
  throw new Error('objective must be a non-empty string');
}

Type guard

function hasObjective(input: { objective: string }): boolean {
  return typeof input.objective === 'string' && input.objective.trim().length > 0;
}

Try / catch

try {
  await runtime.createGoal({ objective });
} catch (err) {
  if (err instanceof Error && err.message === 'objective is required when op=create') {
    return { ok: false, reason: 'empty-objective' };
  }
  throw err;
}

Prevention

When it happens

Trigger: Calling createGoal with objective set to '' or a whitespace-only string (' '), or with an undefined/null coerced into an empty string by upstream code.

Common situations: Tool-call arguments where the LLM supplied an empty objective; UI forms submitted without filling the goal field; config files with objective: "" placeholders.

Understand the failure class

Background: Missing required parameter errors: what 'X is required' and 'the required X param is missing' mean, and how to fix them — this error's family across 27 libraries.

Related errors


AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31). Data as JSON: /api/errors/aa4027f457bb9e95. Report an issue: GitHub.