can1357/oh-my-pi · error

unexpected-stop: no tiny/smol model available for classifica

Error message

unexpected-stop: no tiny/smol model available for classification

What it means

classifyOnline classifies an unexpected stop by asking a small (tiny/smol) model. It resolves the 'tiny' then 'smol' role from settings and the available model list; if neither role resolves to a model it throws this error instead of silently skipping classification.

Source

Thrown at packages/coding-agent/src/session/unexpected-stop-classifier.ts:91

		}
		if (isTinyMemoryLocalModelKey(backend)) {
			return await classifyLocal(text, backend, deps);
		}
		return undefined;
	} catch (error) {
		logger.debug("unexpected-stop: classification failed", {
			error: error instanceof Error ? error.message : String(error),
			backend,
		});
		return undefined;
	}
}

async function classifyOnline(text: string, deps: ClassifyUnexpectedStopDeps): Promise<boolean | undefined> {
	const resolved = resolveRoleSelection(["tiny", "smol"], deps.settings, deps.registry.getAvailable());
	const model = resolved?.model;
	if (!model) {
		throw new Error("unexpected-stop: no tiny/smol model available for classification");
	}
	const apiKey = await deps.registry.getApiKey(model, deps.sessionId);
	if (!apiKey) {
		throw new Error(`unexpected-stop: no API key for ${model.provider}/${model.id}`);
	}
	const metadata = deps.metadataResolver?.(model.provider);
	const maxTokens = ONLINE_REASONING_SAFE_MAX_TOKENS;

	const response = await retryTransientCompletion(
		() =>
			completeSimple(
				model,
				{
					systemPrompt: [CLASSIFIER_SYSTEM_PROMPT],
					messages: [{ role: "user", content: text, timestamp: Date.now() }],
				},
				{
					apiKey: deps.registry.resolver(model, deps.sessionId),

View on GitHub (pinned to 9690622007)

Solutions

  1. Configure an API key/provider so at least one small model is available in the registry.
  2. Set the tiny or smol role explicitly in settings to an available model.
  3. Handle the error upstream in classifyUnexpectedStop and fall back to local/heuristic classification.
  4. Update the model catalog/registry so small models are discoverable.

Example fix

// before
// settings has no tiny/smol role and no providers configured -> throws
// after
await settings.set("small_model", "anthropic/claude-3-5-haiku"); // provides a tiny/smol candidate
Defensive patterns

Strategy: fallback

Validate before calling

const resolved = resolveRoleSelection(["tiny", "smol"], settings, registry.getAvailable());
const canClassifyOnline = resolved?.model != null;

Type guard

function hasSmallModel(r: { model?: unknown }): r is { model: NonNullable<unknown> } {
  return r != null && "model" in r && r.model != null;
}

Try / catch

try {
  verdict = await classifyUnexpectedStop(text, deps);
} catch (err) {
  if (err instanceof Error && err.message.includes("no tiny/smol model available")) {
    verdict = undefined; // skip classification; rely on local heuristic
  } else throw err;
}

Prevention

When it happens

Trigger: classifyUnexpectedStop routes to online classification but neither a tiny nor smol model is present in registry.getAvailable() nor resolvable from settings (e.g. no provider with a small model available).

Common situations: Fresh install with no API providers configured; all providers disabled so the available model list is empty; custom settings removed the tiny/smol role assignments; offline environment where only local models exist but none are registered.

Related errors


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