infiniflow/ragflow · error · Error
Failed to fetch skills
Error message
Failed to fetch skills
What it means
Thrown in web/src/pages/skills/hooks.ts:656 when the raw fetch() to the skill-search endpoint returns a non-OK HTTP status (!response.ok). Unlike other paths that use axios-style services, this hook calls fetch directly, so transport-level failures (404, 401, 500, gateway timeout) surface here before any JSON body is parsed. It indicates the request never reached a successful application-level response.
Source
Thrown at web/src/pages/skills/hooks.ts:656
// Use search API with empty query to list all skills
const response = await fetch('/api/v1/skills/search', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
Authorization: getAuthorization(),
},
body: JSON.stringify({
space_id: spaceId,
query: '', // Empty query = list all
page,
page_size: pageSize,
sort_by: sortBy,
sort_order: sortOrder,
}),
});
if (!response.ok) {
throw new Error('Failed to fetch skills');
}
const result = await response.json();
if (result.code !== 0) {
throw new Error(result.message || 'Failed to fetch skills');
}
const searchSkills = result.data?.skills || [];
const total = result.data?.total || 0;
// If search returned results, use them
if (searchSkills.length > 0) {
const skillsData: Skill[] = searchSkills.map((result: any) => {
const timestamp = pickSkillTimestamp(result);
const skillId = result.skill_id || result.name;
return {
id: skillId,View on GitHub (pinned to 554fb1133a)
Solutions
- Check response.status in the thrown error path (include it in the message) to distinguish 401/404/5xx
- Verify the backend version exposes the skill search endpoint the hook targets
- Confirm the auth token/cookie is attached to the fetch (credentials/headers)
- Test the endpoint directly with curl to see whether the failure is frontend- or server-side
- If 502/504, wait for the backend to be healthy and retry
Example fix
// before
if (!response.ok) {
throw new Error('Failed to fetch skills');
}
// after
if (!response.ok) {
const body = await response.text().catch(() => '');
throw new Error(
`Failed to fetch skills (HTTP ${response.status}) ${body.slice(0, 200)}`,
);
} Defensive patterns
Strategy: retry
Validate before calling
const endpointOk = async (url: string) =>
(await fetch(url, { method: 'HEAD' }).catch(() => ({ ok: false }))).ok; Try / catch
try {
const res = await fetch(url, opts);
if (!res.ok) throw new Error(`HTTP ${res.status}`);
} catch (e) {
if (e.message.includes('HTTP 5')) await backoffRetry();
else throw e;
} Prevention
- Route this call through the shared request client so auth headers and error mapping are consistent
- Include response.status in every thrown HTTP error for diagnosability
When it happens
Trigger: The skill search API route is not deployed (404 after a partial backend upgrade); auth middleware returns 401/403; reverse proxy returns 502/504 when the backend service is down; CORS block in dev when the frontend origin is not allowed; malformed URL built from spaceId.
Common situations: Frontend deployed against an older backend without the search-skills endpoint. Backend container restarting during the request. Dev-server proxy misconfiguration. Session cookie missing after logout.
Related errors
- API rate limit exceeded. ${limit} requests/hour for unauthen
- Repository or path not found. Please check the URL and ensur
- Failed to fetch: ${message}
- Failed to download ${file.path}: ${response.status} ${respon
- No files could be downloaded. Errors:\n${downloadErrors.slic
AI-assisted analysis of infiniflow/ragflow@554fb1133a (2026-08-15).
Data as JSON: /api/errors/3644c14f7585aa22.
Report an issue: GitHub.