{"record":{"id":"998d1541c8ec47cf","repo":"ruvnet/ruflo","slug":"failed-to-load-any-models-from-upstream","errorCode":null,"errorMessage":"Failed to load any models from upstream","messagePattern":"Failed to load any models from upstream","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"critical","filePath":"ruflo/src/ruvocal/src/lib/server/models.ts","lineNumber":246,"sourceCode":"\t\tprepromptUrl: model.prepromptUrl,\n\t\tendpoints:\n\t\t\tmodel.endpoints?.map((endpoint) => {\n\t\t\t\tif (endpoint.type === \"openai\") {\n\t\t\t\t\tconst { type, baseURL } = endpoint;\n\t\t\t\t\treturn { type, baseURL };\n\t\t\t\t}\n\t\t\t\treturn { type: endpoint.type };\n\t\t\t}) ?? null,\n\t\tmultimodal: model.multimodal,\n\t\tmultimodalAcceptedMimetypes: model.multimodalAcceptedMimetypes,\n\t\tsupportsTools: (model as unknown as { supportsTools?: boolean }).supportsTools ?? false,\n\t\tisRouter: model.isRouter,\n\t\thasInferenceAPI: model.hasInferenceAPI,\n\t});\n\nconst applyModelState = (newModels: ProcessedModel[], startedAt: number): ModelsRefreshSummary => {\n\tif (newModels.length === 0) {\n\t\tthrow new Error(\"Failed to load any models from upstream\");\n\t}\n\n\tconst previousIds = new Set(models.map((m) => m.id));\n\tconst previousSignatures = new Map(models.map((m) => [m.id, signatureForModel(m)]));\n\tconst refreshedAt = new Date();\n\tconst durationMs = Date.now() - startedAt;\n\n\tmodels = newModels;\n\tdefaultModel = models[0];\n\ttaskModel = resolveTaskModel(models);\n\tvalidModelIdSchema = createValidModelIdSchema(models);\n\tlastModelRefresh = refreshedAt;\n\tlastModelRefreshDurationMs = durationMs;\n\n\tconst added = newModels.map((m) => m.id).filter((id) => !previousIds.has(id));\n\tconst removed = Array.from(previousIds).filter(\n\t\t(id) => !newModels.some((model) => model.id === id)\n\t);","sourceCodeStart":228,"sourceCodeEnd":264,"githubUrl":"https://github.com/ruvnet/ruflo/blob/fa13ee4ad60ac2090b1480656eb233521790d640/ruflo/src/ruvocal/src/lib/server/models.ts#L228-L264","documentation":"Thrown by applyModelState in models.ts during a model-cache refresh. After buildModels() fetches and normalizes the upstream /models response, applyModelState refuses to install the result if it contains zero models; this protects the running server from wiping a working registry (defaultModel, taskModel, validModelIdSchema) with an empty set.","triggerScenarios":"A refreshModels() cycle where the upstream returned HTTP 200 but an empty model list, or every entry was filtered out during processing (e.g., a filter on multimodal/tools/inference-api availability removed all models). The throw happens before `models = newModels`, so the previous registry survives.","commonSituations":"OpenAI-compatible gateway temporarily exposes no deployments (provider outage, all models disabled); misconfigured OPENAI_BASE_URL pointing to the right host but wrong path that yields an empty-but-valid listSchema payload; custom model filters in buildModels excluding everything.","solutions":["Inspect the [models] logs: 'Parsed models count' shows how many entries survived parsing — if 0, inspect the raw response from ${OPENAI_BASE_URL}/models.","Verify the gateway actually serves models: curl -H \"Authorization: Bearer $OPENAI_API_KEY\" $OPENAI_BASE_URL/models and check data.length.","Check any processing/filter logic in buildModels that can drop models and loosen it if it excludes everything.","Retry the refresh once the upstream repopulates; the old model list stays active until then."],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":"const upstream = await fetch(`${OPENAI_BASE_URL}/models`, { headers: { Authorization: `Bearer ${token}` } });\nconst list = await upstream.json();\nif (!Array.isArray(list.data) || list.data.length === 0) {\n\tthrow new Error(\"Upstream returned no models; keeping previous cache\");\n}","typeGuard":null,"tryCatchPattern":"try {\n\tawait refreshModels();\n} catch (err) {\n\t// previous `models` array is untouched because applyModelState throws before assignment\n\tlogger.error({ err: String(err) }, \"model refresh failed; serving cached models\");\n}","preventionTips":["Smoke-test the gateway's /models endpoint in CI so an empty list is caught before deploy.","Keep the last-known-good model cache durable so a bad refresh never empties a running instance.","Alert on refresh failures and on summary.total dropping to zero."],"tags":["models","refresh","upstream","server"],"backgroundTag":"empty-upstream-response","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"}