Mintplex-Labs/anything-llm · error
Internal Server Error
Error message
Internal Server Error
What it means
HTTP 500 from GET /scheduled-jobs/available-tools. The handler calls ScheduledJob.availableTools() and returns the list. Note a secondary bug: the catch calls response.sendStatus(500).json({ tools: [] }) — Express's sendStatus sends the status code and ends the response, so the chained .json() call either throws or is silently ignored, meaning the client never receives the {tools:[]} fallback body. The 500 itself is triggered when availableTools() throws.
Source
Thrown at server/endpoints/scheduledJobs.js:27
// BackgroundService is a singleton, so `new BackgroundService()` anywhere in
// the codebase returns the same instance that `server/index.js` booted. We
// grab that reference once and reuse it across handlers.
const backgroundService = new BackgroundService();
function scheduledJobEndpoints(app) {
if (!app) return;
// List available tools for job configuration
app.get(
"/scheduled-jobs/available-tools",
[validatedRequest, isSingleUserMode],
async (_request, response) => {
try {
const tools = await ScheduledJob.availableTools();
return response.status(200).json({ tools });
} catch (e) {
console.error(e.message, e);
response.sendStatus(500).json({ tools: [] });
}
}
);
// Get a single run detail
app.get(
"/scheduled-jobs/runs/:runId",
[validatedRequest, isSingleUserMode],
async (request, response) => {
try {
const run = await ScheduledJobRun.get({
id: Number(request.params.runId),
});
if (!run) {
return response
.status(404)
.json({ run: null, error: "Run not found" });
}View on GitHub (pinned to 526360e320)
Solutions
- Check the server log for e.message — it will show which tool or DB query failed.
- Fix the response bug: use response.status(500).json({ tools: [] }) instead of sendStatus(500).json(...) so the fallback body is actually sent.
- Ensure ScheduledJob.availableTools() has a try-catch internally that returns [] on failure rather than throwing.
- Run database migrations and verify the BackgroundService singleton initialized at boot.
Example fix
// before — sendStatus ends the response; .json() is dead code
} catch (e) {
console.error(e.message, e);
response.sendStatus(500).json({ tools: [] });
}
// after — use status() so the json body is actually sent
} catch (e) {
console.error(e.message, e);
response.status(500).json({ tools: [] });
} Defensive patterns
Strategy: fallback
Validate before calling
// This is a GET endpoint with no user-supplied body to validate.
// The only pre-check is ensuring the BackgroundService is initialized.
if (!backgroundService || typeof backgroundService.isReady === 'function' && !backgroundService.isReady())
return response.status(200).json({ tools: [] }); Try / catch
// Fix the sendStatus().json() bug AND make availableTools non-throwing.
try {
const tools = await ScheduledJob.availableTools();
return response.status(200).json({ tools });
} catch (e) {
console.error('available-tools failed:', e.message, e);
// Use status() not sendStatus() so the json body is actually sent
return response.status(200).json({ tools: [] }); // degrade gracefully — empty list, not an error
} Prevention
- Never chain .json() after sendStatus() — sendStatus ends the response. Use response.status(code).json(obj) instead.
- Make ScheduledJob.availableTools() internally catch errors and return [] rather than throwing — a tool discovery failure should not crash the endpoint.
- Consider returning 200 with {tools:[]} instead of 500 — the frontend can still render the page without the tools list.
- Log the error even when falling back, so the root cause isn't hidden.
When it happens
Trigger: GET /scheduled-jobs/available-tools when ScheduledJob.availableTools() throws — e.g., it dynamically discovers agent tools and a tool registration fails, or it reads from a config/DB table that is missing; the endpoint is hit before the BackgroundService singleton has finished initializing; the tool registry includes a plugin that throws on enumeration.
Common situations: Fresh deployment where the tools registry hasn't been seeded; a custom tool plugin that throws during discovery; DB migration not run so the underlying tools table doesn't exist; version upgrade that changed the tool discovery interface.
Understand the failure class
- HTTP status errors: handling 4xx and 5xx responses — how to handle 4xx and 5xx responses properly.
Related errors
- [Conversion Failed]: Could not convert file to .wav format!
- Run not found
- Failed to create workspace
- Failed to create thread
- LMStudio chat: ${this.model} is not valid or defined model f
AI-assisted analysis of Mintplex-Labs/anything-llm@526360e320 (2026-08-13).
Data as JSON: /api/errors/e63dd07ff90a9920.
Report an issue: GitHub.