can1357/oh-my-pi · error · Error

Model ${spec.provider}/${spec.id} resolved to an empty think

Error message

Model ${spec.provider}/${spec.id} resolved to an empty thinking range

What it means

Thrown while building a model's ThinkingConfig in resolve.ts: after applying the rule's efforts (or the fallback effort ladder) the resulting thinking range is empty, so there is no valid effort level to configure. The library refuses to produce a ThinkingConfig with zero efforts since downstream request builders require at least one level.

Source

Thrown at packages/catalog/src/compat/resolve.ts:1133

		"supportsReasoningEffort" in compat &&
		compat.supportsReasoningEffort === false
	) {
		return undefined;
	}
	if (omitsWireReasoningEffort(spec.api, compat)) return undefined;
	const rule = readRuleThinking(axes);
	if (spec.thinking && Array.isArray(spec.thinking.efforts) && spec.thinking.efforts.length > 0) {
		return fillExplicitThinking(spec, facts, compat, spec.thinking, rule);
	}
	if (compat !== undefined && "trustExplicitThinkingOnly" in compat && compat.trustExplicitThinkingOnly === true) {
		return undefined;
	}
	const config: ThinkingConfig = {
		mode: rule.mode ?? defaultThinkingMode(spec, facts),
		efforts: rule.efforts ?? fallbackEfforts(spec, compat),
	};
	if (config.efforts.length === 0) {
		throw new Error(`Model ${spec.provider}/${spec.id} resolved to an empty thinking range`);
	}
	if (rule.defaultLevel !== undefined) config.defaultLevel = rule.defaultLevel;
	const effortMap = mergeEffortMap(spec, facts, rule.effortMap, compat, config.efforts);
	if (effortMap !== undefined) config.effortMap = effortMap;
	if (rule.effortBudgets !== undefined) config.effortBudgets = rule.effortBudgets;
	const supportsDisplay = rule.supportsDisplay ?? defaultSupportsDisplay(spec, facts);
	if (supportsDisplay) config.supportsDisplay = true;
	const requiresEffort =
		rule.requiresEffort ?? (impliesMandatoryReasoning(facts, spec.id) || isQwenTemplateReasoningEffortCompat(compat));
	if (requiresEffort) config.requiresEffort = true;
	if (rule.suppressWhenOff) config.suppressWhenOff = true;
	return config;
}

function defaultSupportsDisplay<TApi extends Api>(spec: ModelSpec<TApi>, facts: IdentityFacts): boolean {
	return (
		(spec.api === "anthropic-messages" || spec.api === "bedrock-converse-stream") &&
		facts.anthropicAdaptiveGenAtLeast("4.7")

View on GitHub (pinned to 9690622007)

Solutions

  1. Check the model's KDL thinking rule and ensure its efforts list uses valid effort identifiers.
  2. Add/fix a class or family rule so fallbackEfforts can supply a ladder for the model.
  3. Regenerate with `bun run gen:compat` and re-run resolution for the model id to confirm a non-empty range.

Example fix

// before (classes/foo.kdl)
rule "foo-5" { efforts ["bogus-level"] }
// after: valid effort ladder
rule "foo-5" { efforts ["low", "medium", "high"] }
Defensive patterns

Strategy: validation

Validate before calling

null

Type guard

null

Try / catch

try {
  const thinking = resolveThinking(spec);
} catch (err) {
  if (err.message.includes("empty thinking range")) {
    logger.error("thinking rule produced no efforts", { model: spec.id });
  }
  throw err;
}

Prevention

When it happens

Trigger: resolveThinkingConfig (or similar) for a spec where rule.efforts and fallbackEfforts both yield [] — e.g. a KDL rule sets an efforts ladder that a later filter/patch axis empties out, or fallbackEfforts returns nothing for an unknown model class.

Common situations: A KDL `thinking` rule listing effort levels that a limits/identity correction axis removes entirely; a newly discovered model with no class/family match so no fallback ladder applies; typo in an effort name in the rule leaving zero recognized levels.

Related errors


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