srbhr/Resume-Matcher · error · Error
Request timed out. If you are running a local LLM, increase
Error message
Request timed out. If you are running a local LLM, increase NEXT_PUBLIC_REQUEST_TIMEOUT_MS (and the backend REQUEST_TIMEOUT_SECONDS to match); otherwise try a shorter job description or check your connection.
What it means
apiFetch wraps fetch with an AbortController timeout; when the request is aborted the browser throws an AbortError, which this code converts into a human-readable timeout Error. The message points at NEXT_PUBLIC_REQUEST_TIMEOUT_MS (frontend) and REQUEST_TIMEOUT_SECONDS (backend) as the knobs to tune.
Source
Thrown at apps/frontend/lib/api/client.ts:80
if (isAbsoluteUrl) {
url = endpoint;
} else if (isApiPath) {
url = resolveRuntimeApiBase(normalizedEndpoint);
}
// Defaults to DEFAULT_TIMEOUT_MS, which tracks the backend's
// REQUEST_TIMEOUT_SECONDS (see next.config.ts proxyTimeout — all three layers
// must agree or the shortest aborts first).
const timeout = timeoutMs ?? DEFAULT_TIMEOUT_MS;
const controller = new AbortController();
const timer = setTimeout(() => controller.abort(), timeout);
try {
return await fetch(url, { ...options, signal: controller.signal });
} catch (error) {
if (error instanceof Error && error.name === 'AbortError') {
throw new Error(
'Request timed out. If you are running a local LLM, increase NEXT_PUBLIC_REQUEST_TIMEOUT_MS (and the backend REQUEST_TIMEOUT_SECONDS to match); otherwise try a shorter job description or check your connection.'
);
}
throw error;
} finally {
clearTimeout(timer);
}
}
/**
* POST request with JSON body.
*/
export async function apiPost<T>(endpoint: string, body: T, timeoutMs?: number): Promise<Response> {
return apiFetch(
endpoint,
{
method: 'POST',
headers: { 'Content-Type': 'application/json' },View on GitHub (pinned to 116f9cc3b0)
Solutions
- Increase NEXT_PUBLIC_REQUEST_TIMEOUT_MS in the frontend env and REQUEST_TIMEOUT_SECONDS in the backend to a value exceeding worst-case LLM latency
- Shorten the job description / reduce the workload sent to the LLM
- Verify the backend is actually processing (check logs); if it is hung, fix the backend/LLM provider connectivity
- Check network path (VPN, proxy) latency between frontend and backend
Example fix
// before (apps/frontend/.env.local) NEXT_PUBLIC_REQUEST_TIMEOUT_MS=30000 // after NEXT_PUBLIC_REQUEST_TIMEOUT_MS=300000
Defensive patterns
Strategy: retry
Validate before calling
const timeoutMs = Number(process.env.NEXT_PUBLIC_REQUEST_TIMEOUT_MS);
if (!timeoutMs || timeoutMs < 60000) {
console.warn('NEXT_PUBLIC_REQUEST_TIMEOUT_MS too low for LLM workloads; set >= 120000');
} Type guard
function isTimeoutError(e: unknown): e is Error {
return e instanceof Error && e.message.startsWith('Request timed out');
} Try / catch
try {
return await apiPost('/analyze', body);
} catch (e) {
if (isTimeoutError(e)) {
// retry once with backoff, or surface tuning hint
return await withBackoff(() => apiPost('/analyze', body), 1);
}
throw e;
} Prevention
- Set NEXT_PUBLIC_REQUEST_TIMEOUT_MS above worst-case LLM latency and keep REQUEST_TIMEOUT_SECONDS in sync
- Warn users before submitting very long job descriptions
- Prefer streaming endpoints for long LLM jobs so no single request stalls
- Alert on abort/timeout rates in the frontend to catch slow backends early
When it happens
Trigger: fetch to any API endpoint exceeds the configured timeout (default NEXT_PUBLIC_REQUEST_TIMEOUT_MS) and the controller aborts — e.g. long LLM generation on POST /analyze, slow local LLM, or stalled network connection.
Common situations: Running a local LLM (Ollama/llama.cpp) that takes minutes on a long job description while the frontend timeout defaults to ~30-60s; backend hanging on an upstream provider; VPN/proxy latency.
Understand the failure class
- Timeouts: ETIMEDOUT, deadlines, and hung requests — what actually expires when a request times out.
Related errors
- ${data.detail || Failed to analyze resume (status ${res.stat
- Failed to load LLM config (status ${res.status}).
- Failed to fetch system status (status ${res.status}).
- Failed to load prompt config (status ${res.status}).
- ${data.detail || Failed to update prompt config (status ${re
AI-assisted analysis of srbhr/Resume-Matcher@116f9cc3b0 (2026-08-28).
Data as JSON: /api/errors/5b2d170b9048b8fe.
Report an issue: GitHub.