{"record":{"id":"8f68420c49d50399","repo":"ruvnet/ruflo","slug":"no-models-available-to-select-task-model","errorCode":null,"errorMessage":"No models available to select task model","messagePattern":"No models available to select task model","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"critical","filePath":"ruflo/src/ruvocal/src/lib/server/models.ts","lineNumber":206,"sourceCode":"\tadded: [],\n\tremoved: [],\n\tchanged: [],\n\ttotal: 0,\n};\n\nlet inflightRefresh: Promise<ModelsRefreshSummary> | null = null;\n\nconst createValidModelIdSchema = (modelList: ProcessedModel[]): z.ZodType<string> => {\n\tif (modelList.length === 0) {\n\t\tthrow new Error(\"No models available to build validation schema\");\n\t}\n\tconst ids = new Set(modelList.map((m) => m.id));\n\treturn z.string().refine((value) => ids.has(value), \"Invalid model id\");\n};\n\nconst resolveTaskModel = (modelList: ProcessedModel[]) => {\n\tif (modelList.length === 0) {\n\t\tthrow new Error(\"No models available to select task model\");\n\t}\n\n\tif (config.TASK_MODEL) {\n\t\tconst preferred = modelList.find(\n\t\t\t(m) => m.name === config.TASK_MODEL || m.id === config.TASK_MODEL\n\t\t);\n\t\tif (preferred) {\n\t\t\treturn preferred;\n\t\t}\n\t}\n\n\treturn modelList[0];\n};\n\nconst signatureForModel = (model: ProcessedModel) =>\n\tJSON.stringify({\n\t\tdescription: model.description,\n\t\tdisplayName: model.displayName,","sourceCodeStart":188,"sourceCodeEnd":224,"githubUrl":"https://github.com/ruvnet/ruflo/blob/fa13ee4ad60ac2090b1480656eb233521790d640/ruflo/src/ruvocal/src/lib/server/models.ts#L188-L224","documentation":"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).","triggerScenarios":"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.","commonSituations":"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.","solutions":["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.","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.","Guard call sites: only invoke taskModel after a successful refresh (check models.length > 0 or lastModelRefresh > epoch).","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."],"exampleFix":"// before\nconst tm = resolveTaskModel(models); // throws when registry empty\n\n// after\nif (models.length === 0) {\n\tthrow new Error(\"Model registry is empty; wait for the initial refresh to succeed\");\n}\nconst tm = resolveTaskModel(models);","handlingStrategy":"validation","validationCode":"// before touching the registry\nimport { models, lastModelRefresh } from \"$lib/server/models\";\n\nif (models.length === 0 || lastModelRefresh.getTime() === 0) {\n\tthrow new Error(\"Model registry not populated yet; wait for initial refresh\");\n}","typeGuard":"function hasModels<T>(list: T[]): list is [T, ...T[]] {\n\treturn list.length > 0;\n}","tryCatchPattern":null,"preventionTips":["Treat an empty upstream model list as a deployment blocker and fail startup loudly.","Expose readiness from the model-refresh summary (lastModelRefreshSummary.total > 0) and gate traffic on it.","Monitor the periodic refresh; alert when it throws so the registry never silently stays empty."],"tags":["models","startup","configuration","server"],"backgroundTag":"empty-model-registry","analyzedSha":"fa13ee4ad60ac2090b1480656eb233521790d640","analyzedAt":"2026-08-18T21:34:22.708Z","contentChangedAt":"2026-08-18T21:34:22.708Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}