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

  1. Check response.status in the thrown error path (include it in the message) to distinguish 401/404/5xx
  2. Verify the backend version exposes the skill search endpoint the hook targets
  3. Confirm the auth token/cookie is attached to the fetch (credentials/headers)
  4. Test the endpoint directly with curl to see whether the failure is frontend- or server-side
  5. 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

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


AI-assisted analysis of infiniflow/ragflow@554fb1133a (2026-08-15). Data as JSON: /api/errors/3644c14f7585aa22. Report an issue: GitHub.