DIYgod/RSSHub · error · Error

Unable to access the Locals server function (${response.stat

Error message

Unable to access the Locals server function (${response.status}).

What it means

Thrown by `requestServerFunction` (lib/routes/locals/feed.ts:363) when the POST to `https://locals.com/_server` returns a non-2xx status. The message embeds `response.status` so the exact HTTP code surfaces. A non-ok response typically means the `X-Server-Id`/`X-Server-Instance` headers are stale, the session cookie is invalid/expired, or Locals rate-limits/blocks the request.

Source

Thrown at lib/routes/locals/feed.ts:364

        filter,
    };
}

async function requestServerFunction<T>(session: string, id: string, key: string, args: unknown[]) {
    const response = await ofetch.raw(`${rootUrl}/_server`, {
        body: createRequestBody(args),
        headers: {
            'Content-Type': 'application/json',
            ...getRequestHeaders(session),
            'X-Server-Id': id,
            'X-Server-Instance': key,
        },
        method: 'POST',
        responseType: 'text',
    });

    if (!response.ok) {
        throw new Error(`Unable to access the Locals server function (${response.status}).`);
    }

    return parseUnknownResponse<T>(response._data!, key);
}

function fetchCommunityInfo(community: string, session: string) {
    return cache.tryGet(`locals:community:${community}`, async () => {
        const html = await fetchContentPage(community, session);
        return extractCommunityInfo(html, community);
    });
}

async function fetchFeedData(communityId: number, community: string, session: string, serverId: string, filter: ContentFilter | undefined, contentType: string | undefined) {
    const requestFilter = filter ? contentFilterMap[filter] : undefined;
    const filters = requestFilter ? [requestFilter] : Object.values(contentFilterMap);

    const responses = await Promise.all(
        filters.map((currentFilter) =>

View on GitHub (pinned to bed535e087)

Solutions

  1. Refresh `config.locals.session` with a current authenticated cookie from a logged-in browser.
  2. Cache-bust `locals:action-ids:<community>` so a fresh `serverId`/`key` is resolved.
  3. Inspect the embedded status: 401/403 -> session; 400 -> stale id or bad body; 429 -> back off / rotate IP.
  4. Retry once after clearing the session-dependent caches; if it persists, the server-function contract changed and the route needs an update.

Example fix

// before: single shot, surfaces only the status
if (!response.ok) {
    throw new Error(`Unable to access the Locals server function (${response.status}).`);
}

// after: include the response body snippet for faster diagnosis
if (!response.ok) {
    const snippet = String(response._data ?? '').slice(0, 200);
    throw new Error(`Unable to access the Locals server function (${response.status}): ${snippet}`);
}
Defensive patterns

Strategy: retry

Validate before calling

// Pre-flight: ensure session + action ids look fresh before calling /_server.
async function preflightLocalsServer(community: string): Promise<void> {
    if (!config.locals?.session) throw new Error('Locals session missing');
    // ensure action ids resolve (throws 325/326 with a clearer message)
    await resolveActionIds(community, config.locals.session);
}

Type guard

function isServerFunctionOk(r: { ok: boolean; status: number }): boolean { return r.ok; }

Try / catch

try {
    return await requestServerFunction<T>(session, id, key, args);
} catch (e) {
    const status = (e as Error).message.match(/\((\d{3})\)/)?.[1];
    if (status === '401' || status === '403') throw new Error('Locals session invalid/expired');
    if (status === '400') { await cache.delete('locals:action-ids:' + community); /* retry once */ }
    if (status === '429') { await new Promise(r => setTimeout(r, 5000)); /* retry once */ }
    throw e;
}

Prevention

When it happens

Trigger: Expired `config.locals.session` cookie (401/403); stale `serverId`/`key` cached from an older bundle (400/500); rate limiting (429); Locals temporarily down (5xx); malformed request body from `createRequestBody`.

Common situations: Session cookie rotated by Locals; cache holding an action id from before a deploy; running RSSHub from an IP Locals blocks; clock skew affecting signed payloads.

Related errors


AI-assisted analysis of DIYgod/RSSHub@bed535e087 (2026-08-12). Data as JSON: /api/errors/36a0424ea9dbe5db. Report an issue: GitHub.