ruvnet/ruflo · error · Error

No models available to select task model

Error message

No models available to select task model

What it means

Thrown by resolveTaskModel when the supplied modelList is empty. resolveTaskModel picks the model used for background tasks (summaries, titles, tooling) using config.TASK_MODEL when set, otherwise models[0]. Like createValidModelIdSchema, it is called from applyModelState after the empty-list guard, so reaching it means it was called without that guard or models were cleared concurrently.

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 6b01dc5a68)

Solutions

  1. Only call resolveTaskModel after confirming modelList.length > 0.
  2. If config.TASK_MODEL references a model that is not in the list, log a warning and fall back to models[0] rather than failing - but only when the list itself is non-empty.
  3. Keep the applyModelState sequencing intact so this guard is exercised before resolveTaskModel.

Example fix

// before
taskModel = resolveTaskModel(models);

// after
if (models.length === 0) {
  throw new Error('Cannot resolve task model: model list is empty');
}
taskModel = resolveTaskModel(models);
Defensive patterns

Strategy: validation

Validate before calling

function safeResolveTaskModel(models: ProcessedModel[]) {
  if (models.length === 0) throw new Error("Cannot resolve task model: empty list");
  return resolveTaskModel(models);
}

Type guard

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

Try / catch

try { taskModel = resolveTaskModel(models); }
catch (e) {
  if (e instanceof Error && /No models available to select task model/.test(e.message)) {
    // skip task model update; keep previous value
  } else throw e;
}

Prevention

When it happens

Trigger: Direct call to resolveTaskModel([]); or a code path that resets the global models array to [] and then calls refreshModels/resolveTaskModel. Normally unreachable because applyModelState checks newModels.length === 0 first (throwing error 34 instead).

Common situations: Refactor that introduces a second call site for resolveTaskModel without an empty check; test harness that stubs models as []; hot-reload clearing module state during development.

Related errors


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