can1357/oh-my-pi · error · Error
cannot complete goal because no goal is active
Error message
cannot complete goal because no goal is active
What it means
completeGoalFromTool finalizes the session's active goal, so it throws when no goal exists in the state — there is nothing to mark complete. It is the tool-invoked completion path and requires a live GoalModeState with a goal.
Source
Thrown at packages/coding-agent/src/goals/runtime.ts:478
const dropped = { ...state.goal, status: "dropped" as const, updatedAt: this.#now() };
this.#clearActiveAccounting();
this.#budgetReportedFor = undefined;
await this.#host.emit({
type: "goal_updated",
goal: dropped,
state: { ...state, enabled: false, goal: dropped },
});
await this.#commitState(undefined, { persist: "none", emit: false });
return dropped;
});
}
async completeGoalFromTool(): Promise<Goal> {
return await this.#withAccounting(async () => {
await this.#flushUsageLocked("suppressed");
const state = this.#getStateClone();
if (!state?.goal) {
throw new Error("cannot complete goal because no goal is active");
}
if (state.goal.status === "complete") {
throw new Error("goal is already complete");
}
if (state.goal.status === "dropped") {
throw new Error("cannot complete a dropped goal");
}
state.enabled = false;
state.goal.status = "complete";
state.goal.updatedAt = this.#now();
state.mode = "exiting";
state.reason = "completed";
this.#clearActiveAccounting();
this.#budgetReportedFor = undefined;
await this.#commitState(state, { persist: "goal" });
return state.goal;
});
}View on GitHub (pinned to 9690622007)
Solutions
- Ensure a goal exists (createGoal) before attempting completion
- Check getState()?.goal before emitting the complete op
- Fix the agent flow so the completion tool is only exposed while a goal is active
Example fix
// before
await runtime.completeGoalFromTool(); // throws if none
// after
const state = host.getState();
if (!state?.goal) throw new Error('No goal to complete');
await runtime.completeGoalFromTool(); Defensive patterns
Strategy: validation
Validate before calling
const state = host.getState();
if (!state?.goal) throw new Error('completeGoalFromTool requires an existing goal'); Type guard
function hasGoal(state: { goal?: unknown } | undefined | null): boolean {
return !!state?.goal;
} Try / catch
try {
await runtime.completeGoalFromTool();
} catch (err) {
if (err instanceof Error && err.message.includes('no goal is active')) {
return { ok: false, reason: 'no-goal' }; // surface as no-op to the agent
}
throw err;
} Prevention
- Only expose the goal-complete tool when a goal is active in the session
- Check state before emitting tool calls from agent logic
- Ensure goal state is persisted/restored across session boundaries
When it happens
Trigger: Invoking the goal-complete tool on a session with no goal created; calling it after the goal was dropped (dropped has its own message) or after state was cleared by a restart; double-invocation after state reset.
Common situations: LLM emitting the completion tool without the goal op having run; session restored without goal persistence; flows that complete the goal then call the tool again in a new context.
Understand the failure class
Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.
Related errors
- cannot create a new goal because this session already has a
- cannot replace goal because no goal is active
- No paused goal.
- Goal is already complete.
- goal is already complete
AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31).
Data as JSON: /api/errors/51b3ef06f2269256.
Report an issue: GitHub.