ruvnet/ruflo · error
No endpoints configured. This build requires…
Error message
No endpoints configured. This build requires OpenAI-compatible endpoints.
What it means
This build of chat-ui speaks exclusively to OpenAI-compatible APIs, so every processed model must carry at least one endpoint. getEndpoint() (models.ts:135), invoked lazily when a generation actually starts, throws when a model's endpoints array is missing or empty — the model was listed/selectable but cannot be served.
Solutions
- Add an explicit endpoint to the model entry: "endpoints": [{ "type": "openai", "baseURL": "...", "apiKey": "..." }]
- Or remove the broken MODELS override so models get the default OpenAI endpoint built from OPENAI_BASE_URL/OPENAI_API_KEY
- Validate overrides at startup (every entry has endpoints?.length > 0) and log offending model ids before users hit it
- If the model should not be selectable, mark it unlisted or remove it from the registry
Example fix
// before (.env)
MODELS=[{"id":"my-model","name":"My Model"}] // getEndpoint() throws at generation time
// after
MODELS=[{
"id":"my-model",
"name":"My Model",
"endpoints":[{"type":"openai","baseURL":"https://router.huggingface.co/v1"}]
}] Defensive patterns
Strategy: validation
Validate before calling
function assertModelServable(m: { endpoints?: { type: string }[] }): void {
if (!m.endpoints || m.endpoints.length === 0) {
throw new Error(`Model ${String(m)} has no endpoints and cannot serve generations`);
}
}
assertModelServable(model);
const endpoint = await model.getEndpoint(); Type guard
type ServableModel = { endpoints: { type: string }[] } & Record<string, unknown>;
function isServable(m: { endpoints?: unknown[] }): m is ServableModel {
return Array.isArray(m.endpoints) && m.endpoints.length > 0;
} Prevention
- Validate MODELS overrides at startup: every entry must include a non-empty endpoints array
- Filter unservable models out of the picker (unlisted) so users never select them
- Log model id alongside the error — getEndpoint() throws long after config load
When it happens
Trigger: Selecting a model whose config has no endpoints: a MODELS env override entry without an "endpoints" array (or with "endpoints": []), or a model synthesized from /v1/models plus overrides such that no endpoint was attached. The throw happens on message send, not at startup.
Common situations: Hand-written MODELS JSON copied from other chat-ui forks where endpoints were optional; an override meant to tweak a model accidentally replacing its endpoints; a router returning model ids that no longer match the override shapes so endpoint attachment is skipped.
Related errors
- Only 'openai' endpoint type is supported in this build
- Invalid completion type
- No models available to select task model
- OPENAI_BASE_URL not set
- agents must have ≥1 entry
AI-assisted analysis of ruvnet/ruflo@fa13ee4ad6 (2026-08-18).
Data as JSON: /api/errors/07894dab46da43a9.
Report an issue: GitHub.
Appendix: source
Thrown at ruflo/src/ruvocal/src/lib/server/models.ts:135
return parts.join("\n\n");
};
}
const processModel = async (m: ModelConfig) => ({
...m,
chatPromptRender: await getChatPromptRender(m),
id: m.id || m.name,
displayName: m.displayName || m.name,
preprompt: m.prepromptUrl ? await fetch(m.prepromptUrl).then((r) => r.text()) : m.preprompt,
parameters: { ...m.parameters, stop_sequences: m.parameters?.stop },
unlisted: m.unlisted ?? false,
});
const addEndpoint = (m: Awaited<ReturnType<typeof processModel>>) => ({
...m,
getEndpoint: async (): Promise<Endpoint> => {
if (!m.endpoints || m.endpoints.length === 0) {
throw new Error("No endpoints configured. This build requires OpenAI-compatible endpoints.");
}
// Only support OpenAI-compatible endpoints in this build
const endpoint = m.endpoints[0];
if (endpoint.type !== "openai") {
throw new Error("Only 'openai' endpoint type is supported in this build");
}
return await endpoints.openai({ ...endpoint, model: m });
},
});
type InternalProcessedModel = Awaited<ReturnType<typeof addEndpoint>> & {
isRouter: boolean;
hasInferenceAPI: boolean;
};
const inferenceApiIds: string[] = [];
const getModelOverrides = (): ModelOverride[] => {View on GitHub (pinned to fa13ee4ad6)