ruvnet/ruflo · critical

No models available to select task model

Error message

No models available to select task model

What it means

Thrown by resolveTaskModel in the server model registry (ruflo/src/ruvocal/src/lib/server/models.ts). The chat UI derives a 'task model' (used for background/title-generation tasks) from the processed model list fetched from OPENAI_BASE_URL/models; an empty list is unrecoverable because the function must return a concrete ProcessedModel. In practice applyModelState guards emptiness first, so this fires when resolveTaskModel is called directly with an empty registry (e.g., startup before the first successful refresh).

Solutions

  1. Fix the root cause upstream first: curl ${OPENAI_BASE_URL}/models with the same OPENAI_API_KEY and confirm it returns a non-empty data array.
  2. If the first refresh failed, address that error (see 'Failed to fetch ...' / 'OPENAI_BASE_URL not set') so the registry populates and resolveTaskModel gets a non-empty list.
  3. Guard call sites: only invoke taskModel after a successful refresh (check models.length > 0 or lastModelRefresh > epoch).
  4. If TASK_MODEL is set, verify it matches a model id or name returned by upstream, otherwise it silently falls back to models[0] once the list is non-empty.

Example fix

// before
const tm = resolveTaskModel(models); // throws when registry empty

// after
if (models.length === 0) {
	throw new Error("Model registry is empty; wait for the initial refresh to succeed");
}
const tm = resolveTaskModel(models);
Defensive patterns

Strategy: validation

Validate before calling

// before touching the registry
import { models, lastModelRefresh } from "$lib/server/models";

if (models.length === 0 || lastModelRefresh.getTime() === 0) {
	throw new Error("Model registry not populated yet; wait for initial refresh");
}

Type guard

function hasModels<T>(list: T[]): list is [T, ...T[]] {
	return list.length > 0;
}

Prevention

When it happens

Trigger: Calling resolveTaskModel([]) or any code path that reaches it while the global `models` array is still empty: server booted but the initial buildModels() fetch has not completed or failed; upstream /models returned an empty array; or a test/helper invokes the function on an empty list.

Common situations: Self-hosted deployments where OPENAI_BASE_URL points at a gateway that returns an empty `data` array; startup race where a request needing taskModel arrives before the first model refresh; TASK_MODEL env var set but the registry never populated because the upstream fetch failed.

Related errors


AI-assisted analysis of ruvnet/ruflo@fa13ee4ad6 (2026-08-18). Data as JSON: /api/errors/8f68420c49d50399. Report an issue: GitHub.

Appendix: source

Thrown at ruflo/src/ruvocal/src/lib/server/models.ts:206

	added: [],
	removed: [],
	changed: [],
	total: 0,
};

let inflightRefresh: Promise<ModelsRefreshSummary> | null = null;

const createValidModelIdSchema = (modelList: ProcessedModel[]): z.ZodType<string> => {
	if (modelList.length === 0) {
		throw new Error("No models available to build validation schema");
	}
	const ids = new Set(modelList.map((m) => m.id));
	return z.string().refine((value) => ids.has(value), "Invalid model id");
};

const resolveTaskModel = (modelList: ProcessedModel[]) => {
	if (modelList.length === 0) {
		throw new Error("No models available to select task model");
	}

	if (config.TASK_MODEL) {
		const preferred = modelList.find(
			(m) => m.name === config.TASK_MODEL || m.id === config.TASK_MODEL
		);
		if (preferred) {
			return preferred;
		}
	}

	return modelList[0];
};

const signatureForModel = (model: ProcessedModel) =>
	JSON.stringify({
		description: model.description,
		displayName: model.displayName,

View on GitHub (pinned to fa13ee4ad6)