ruvnet/ruflo · critical
No models available to build validation schema
Error message
No models available to build validation schema
What it means
createValidModelIdSchema (models.ts:198) builds the zod validator that later rejects unknown model ids in API requests; with an empty model list there is nothing to validate against, so it throws. It is called from applyModelState after refresh; note applyModelState already throws "Failed to load any models from upstream" for empty lists first, so this guard fires only via other paths that pass an empty registry.
Solutions
- Check GET {OPENAI_BASE_URL}/models with the same token (Authorization: Bearer ...) — confirm it returns a non-empty data array
- Fix or relax MODELS overrides so at least one model survives filtering
- Verify the token has entitlements for the router/gateway and OPENAI_BASE_URL is the correct base (e.g. ends in /v1)
- Fail startup with a clear message when the catalog is empty instead of letting the schema builder throw later
Example fix
// before
const parsed = listSchema.parse(json);
const models = parsed.data.map(processModel);
applyModelState(models, startedAt); // empty list -> guard throws
// after
if (parsed.data.length === 0) {
throw new Error(
`No models returned by ${baseURL}/models — check token entitlements and MODELS overrides`
);
} Defensive patterns
Strategy: validation
Validate before calling
if (models.length === 0) {
throw new Error(
`No models from ${OPENAI_BASE_URL}/models — check token entitlements and MODELS overrides`
);
}
validModelIdSchema = createValidModelIdSchema(models); Type guard
function hasModels(list: unknown[]): list is [unknown, ...unknown[]] {
return list.length > 0;
} Prevention
- Health-check {OPENAI_BASE_URL}/models in CI and on boot; fail fast on an empty catalog
- Keep at least one known-good model entry (override or gateway default) as a floor
- Alert when refreshModels() reports total: 0 rather than waiting for schema construction to throw
When it happens
Trigger: buildModels()/refreshModels() yielding zero usable models — {OPENAI_BASE_URL}/models returned an empty data array, every model was filtered out by MODELS overrides, or listSchema parsing produced [] — and the empty list reaching schema creation.
Common situations: OPENAI_BASE_URL pointing at a gateway/account with no model entitlements (valid token, empty catalog); overly restrictive MODELS overrides filtering everything; a router whose /models response shape changed so listSchema parses zero entries; fresh deploy before the upstream catalog is provisioned.
Related errors
- No models available to select task model
- OPENAI_BASE_URL not set
- agent must be an object
- anchor task has no query
- anchor task requires non-empty string labels
AI-assisted analysis of ruvnet/ruflo@fa13ee4ad6 (2026-08-18).
Data as JSON: /api/errors/a1fd45e90bbeec66.
Report an issue: GitHub.
Appendix: source
Thrown at ruflo/src/ruvocal/src/lib/server/models.ts:198
export let defaultModel!: ProcessedModel;
export let taskModel!: ProcessedModel;
export let validModelIdSchema: z.ZodType<string> = z.string();
export let lastModelRefresh = new Date(0);
export let lastModelRefreshDurationMs = 0;
export let lastModelRefreshSummary: ModelsRefreshSummary = {
refreshedAt: new Date(0),
durationMs: 0,
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;
}
}View on GitHub (pinned to fa13ee4ad6)