can1357/oh-my-pi · error
unexpected-stop: online classification failed: ${response.er
Error message
unexpected-stop: online classification failed: ${response.errorMessage ?? "unknown error"} What it means
The online classifier's completion call returned stopReason === 'error'; classifyOnline surfaces the provider's errorMessage wrapped in this prefix. It is thrown after retryTransientCompletion exhausted retries, so the underlying failure is persistent (auth, rate limit, network, or model rejection).
Source
Thrown at packages/coding-agent/src/session/unexpected-stop-classifier.ts:120
completeSimple(
model,
{
systemPrompt: [CLASSIFIER_SYSTEM_PROMPT],
messages: [{ role: "user", content: text, timestamp: Date.now() }],
},
{
apiKey: deps.registry.resolver(model, deps.sessionId),
maxTokens,
disableReasoning: true,
metadata,
signal: deps.signal,
},
),
{ signal: deps.signal },
);
if (response.stopReason === "error") {
throw new Error(`unexpected-stop: online classification failed: ${response.errorMessage ?? "unknown error"}`);
}
const outputText = response.content
.filter((part): part is { type: "text"; text: string } => part.type === "text")
.map(part => part.text)
.join("\n");
return parseUnexpectedStopClassification(outputText);
}
async function classifyLocal(
text: string,
modelKey: string,
deps: ClassifyUnexpectedStopDeps,
): Promise<boolean | undefined> {
if (!isTinyMemoryLocalModelKey(modelKey)) {
throw new Error(`unexpected-stop: unsupported local classifier model: ${modelKey}`);
}
const builtPrompt = prompt.render(unexpectedStopClassifierPrompt, { message: text });View on GitHub (pinned to 9690622007)
Solutions
- Read the embedded response.errorMessage to identify the root cause (auth vs rate limit vs network).
- Fix the underlying credential or network issue and retry.
- Increase maxTokens if the error indicates the reasoning model exceeded the token budget.
- Verify the tiny/smol model is still served by the provider (deprecated ids return errors).
Defensive patterns
Strategy: retry
Try / catch
try {
verdict = await classifyUnexpectedStop(text, deps);
} catch (err) {
if (err instanceof Error && err.message.startsWith("unexpected-stop: online classification failed:")) {
logger.warn("stop classification failed", { detail: err.message });
verdict = undefined; // or retry with backoff for transient causes
} else throw err;
} Prevention
- Inspect the embedded errorMessage to distinguish auth (fix keys), rate limit (backoff), and network (retry) causes.
- Keep ONLINE_REASONING_SAFE_MAX_TOKENS large enough for reasoning-style small models.
- Add jittered backoff around classification calls to avoid 429s.
- Pin the tiny/smol model to a stable, non-deprecated id.
When it happens
Trigger: The streaming completion request to the tiny/smol model fails with an error stop reason on every retry: 401/403 from bad key, 429 rate limits, network outage, or the model rejects the request shape (e.g. maxTokens too small for a reasoning model).
Common situations: Expired/invalid API key; provider outage; rate limiting from bursty classification calls; using a reasoning model with ONLINE_REASONING_SAFE_MAX_TOKENS too low causing truncation errors; proxy/firewall blocking the endpoint.
Related errors
- ambiguous family for `${model}`: `${tied[0]}` and `${tied[1]
- ambiguous class for `${lower}`: `${tied[0]}` and `${tied[1]}
- auto-thinking: unparseable local classification: ${JSON.stri
- ${response.errorMessage ?? "completion() request failed."}
- unexpected-stop: no tiny/smol model available for classifica
AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31).
Data as JSON: /api/errors/a9768cd3cabf7829.
Report an issue: GitHub.