{"record":{"id":"07894dab46da43a9","repo":"ruvnet/ruflo","slug":"no-endpoints-configured-this-build-requires-opena","errorCode":null,"errorMessage":"No endpoints configured. This build requires OpenAI-compatible endpoints.","messagePattern":"No endpoints configured\\. This build requires OpenAI-compatible endpoints\\.","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"ruflo/src/ruvocal/src/lib/server/models.ts","lineNumber":135,"sourceCode":"\t\treturn parts.join(\"\\n\\n\");\n\t};\n}\n\nconst processModel = async (m: ModelConfig) => ({\n\t...m,\n\tchatPromptRender: await getChatPromptRender(m),\n\tid: m.id || m.name,\n\tdisplayName: m.displayName || m.name,\n\tpreprompt: m.prepromptUrl ? await fetch(m.prepromptUrl).then((r) => r.text()) : m.preprompt,\n\tparameters: { ...m.parameters, stop_sequences: m.parameters?.stop },\n\tunlisted: m.unlisted ?? false,\n});\n\nconst addEndpoint = (m: Awaited<ReturnType<typeof processModel>>) => ({\n\t...m,\n\tgetEndpoint: async (): Promise<Endpoint> => {\n\t\tif (!m.endpoints || m.endpoints.length === 0) {\n\t\t\tthrow new Error(\"No endpoints configured. This build requires OpenAI-compatible endpoints.\");\n\t\t}\n\t\t// Only support OpenAI-compatible endpoints in this build\n\t\tconst endpoint = m.endpoints[0];\n\t\tif (endpoint.type !== \"openai\") {\n\t\t\tthrow new Error(\"Only 'openai' endpoint type is supported in this build\");\n\t\t}\n\t\treturn await endpoints.openai({ ...endpoint, model: m });\n\t},\n});\n\ntype InternalProcessedModel = Awaited<ReturnType<typeof addEndpoint>> & {\n\tisRouter: boolean;\n\thasInferenceAPI: boolean;\n};\n\nconst inferenceApiIds: string[] = [];\n\nconst getModelOverrides = (): ModelOverride[] => {","sourceCodeStart":117,"sourceCodeEnd":153,"githubUrl":"https://github.com/ruvnet/ruflo/blob/6b01dc5a687b26b3e218f796de45ec51f8fa9e8c/ruflo/src/ruvocal/src/lib/server/models.ts#L117-L153","documentation":"Thrown by the getEndpoint closure created in addEndpoint (models.ts) when a processed model has no endpoints array or an empty one. chat-ui's OpenAI-only build requires every model to resolve to an OpenAI-compatible endpoint at call time; buildModels normally injects endpoints:[{type:'openai', baseURL}] for every upstream model, so this throws when a MODELS override or a manually-constructed ProcessedModel (e.g. the router alias) ends up with no endpoints.","triggerScenarios":"A MODELS override entry that explicitly sets endpoints: [] (or omits endpoints while also removing the default); a model constructed by another code path (router alias, custom plugin) that did not populate endpoints; calling model.getEndpoint() on such a model during a chat completion.","commonSituations":"Migration from a chat-ui config that relied on 'tgi'/'aws'/'anthropic' endpoints that this OpenAI-only build ignores; hand-edited MODELS env that strips endpoints; a model override that sets only display fields and clobbers the inherited endpoints via spread semantics.","solutions":["Ensure each MODELS override entry either omits endpoints (so the default OpenAI endpoint is inherited) or explicitly provides endpoints: [{type:'openai', baseURL: '...'}].","Audit overrides for accidental endpoints: [] or endpoints set to a non-array.","If you need a non-OpenAI backend, switch to a build that supports additional endpoint types."],"exampleFix":"// before (MODELS env)\n[{\"id\":\"my-model\",\"displayName\":\"My Model\",\"endpoints\":[]}]\n\n// after\n[{\"id\":\"my-model\",\"displayName\":\"My Model\"}]\n// or explicit:\n[{\"id\":\"my-model\",\"endpoints\":[{\"type\":\"openai\",\"baseURL\":\"https://router.huggingface.co/v1\"}]}]","handlingStrategy":"validation","validationCode":"function modelsHaveEndpoints(models: { endpoints?: unknown }[]): boolean {\n  return models.every((m) => Array.isArray(m.endpoints) && m.endpoints.length > 0);\n}\n// before assigning MODELS env, ensure no entry strips endpoints to [].","typeGuard":"function hasOpenAiEndpoint(m: { endpoints?: { type?: string }[] }): boolean {\n  return Array.isArray(m.endpoints) && m.endpoints.length > 0 && m.endpoints[0]?.type === \"openai\";\n}","tryCatchPattern":"try { const ep = await model.getEndpoint(); }\ncatch (e) {\n  if (e instanceof Error && /No endpoints configured/.test(e.message)) {\n    // fall back to default OpenAI endpoint or remove model from the registry\n    return endpoints.openai({ type: \"openai\", baseURL: openaiBaseUrl, model });\n  }\n  throw e;\n}","preventionTips":["In MODELS overrides, either omit endpoints (inherit the default OpenAI endpoint) or set endpoints:[{type:'openai', baseURL:'...'}].","Never set endpoints:[] in an override.","Add a config lint step that rejects overrides with empty/non-openai endpoint arrays in this build."],"tags":["models","config","endpoints","openai"],"backgroundTag":null,"analyzedSha":"6b01dc5a687b26b3e218f796de45ec51f8fa9e8c","analyzedAt":"2026-08-12T13:20:50.148Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}