Mintplex-Labs/anything-llm · error
No model router found for this workspace.
Error message
No model router found for this workspace.
What it means
AnythingLLMModelRouter.resolve() must load a model-router configuration before it can route; it calls ModelRouterService.resolveRouterForWorkspace(), which returns null when the workspace has no router_id or the referenced router record cannot be loaded (e.g. deleted). resolve() then throws this error, so no delegate LLM provider is ever created.
Solutions
- Open workspace settings and (re)select a model router so router_id is set on the workspace, then retry
- If the router was deleted, create a new model router and assign it to the workspace
- Verify the workspace record actually has a non-null router_id — null always produces this error
- Restart the server (or let the router cache invalidate) after router configuration changes
Example fix
// before
const router = new AnythingLLMModelRouter(workspace);
await router.resolve(ctx); // throws when workspace.router_id is null
// after
if (!workspace.router_id)
throw new Error('Attach a model router to this workspace first');
await router.resolve(ctx); Defensive patterns
Strategy: validation
Validate before calling
const svc = ModelRouterService.getInstance();
const router = await svc.resolveRouterForWorkspace(workspace);
if (!router)
throw new Error('Workspace has no model router attached — assign one in workspace settings'); Type guard
function hasRouterAttached(workspace) {
return typeof workspace?.router_id === 'number' && workspace.router_id > 0;
} Try / catch
try {
await modelRouter.resolve(context, { user, thread });
} catch (e) {
if (e.message === 'No model router found for this workspace.') {
// fall back to the workspace default LLM, or prompt the user to attach a router
}
throw e;
} Prevention
- Assign a router to the workspace before enabling router mode
- When deleting routers, detach dependent workspaces first
- Invalidate the router cache (or restart) after router configuration changes
- Guard resolve() calls with hasRouterAttached(workspace)
When it happens
Trigger: Workspace chat uses the model router but workspace.router_id is null (router never assigned or detached); the referenced router row was deleted while workspaces still point at it; a stale in-process workspace object is used after the router was removed; calling resolve() on a workspace whose router assignment is still mid-save.
Common situations: Admin deletes a model router that workspaces still reference; DB restore/migration drops model_routers rows; race between router reassignment and an incoming chat request.
Related errors
- Bad Request
- Internal Server Error
- KoboldCPP must have a valid base path to use for the api.
- KoboldCPP must have a valid model set.
- LiteLLM must have a valid base path to use for the api.
AI-assisted analysis of Mintplex-Labs/anything-llm@3aec848f28 (2026-08-18).
Data as JSON: /api/errors/2a9cdc6b23a9c143.
Report an issue: GitHub.
Appendix: source
Thrown at server/utils/AiProviders/modelRouter/index.js:38
/**
* Resolve the route and instantiate the delegate LLM provider.
* Must be called before any chat methods.
*
* Flow:
* 1. Evaluate calculated rules (always — they're free)
* 2. Evaluate LLM rules (uses cache to avoid expensive calls)
* 3. If nothing matched, use the sticky route (previous model stays)
* 4. If sticky expired, fall back to the default model
*
* @param {Object} context - { prompt, conversationHistory, conversationTokenCount }
* @param {Object} opts - { user, thread }
*/
async resolve(context = {}, { user = null, thread = null } = {}) {
this.router = await this.routerService.resolveRouterForWorkspace(
this.workspace
);
if (!this.router)
throw new Error("No model router found for this workspace.");
const rules = this.router.rules || [];
const stickyMs = (this.router.cooldown_seconds ?? 300) * 1000;
this._routeKey = this.routerService.routeCacheKey(
user?.id,
this.workspace.slug,
thread?.slug
);
this.routerService.logRoutingContext(this.router, rules, context);
// Step 1: Calculated rules (always re-evaluated, they're instant)
const calcResult = this.routerService.evaluateCalculatedRules(
rules,
context
);
if (calcResult) {
this.resolvedRoute = calcResult;View on GitHub (pinned to 3aec848f28)