DIYgod/RSSHub · error · Error

${tagResponse.msg}

Error message

${tagResponse.msg}

What it means

Followin's internal API at /feed/list/tag returns a JSON envelope where success is signaled by code === 2000. Any other code indicates the request was rejected (invalid/expired anti-bot tokens, bad tagId, rate limiting) and the API's msg field carries the human-readable reason, which is re-thrown verbatim. The endpoint is anti-crawler protected and depends on x-bparam and x-gtoken headers derived from the site's build session.

Source

Thrown at lib/routes/followin/tag.ts:56

        const { base_info: tagInfo } = queries.find((q) => q.queryKey[0] === '/tag/info/v2').state.data;
        return tagInfo;
    });

    const gToken = await getGToken();
    const bParam = getBParam(lang);
    const { data: tagResponse } = await got.post(`${apiUrl}/feed/list/tag`, {
        headers: {
            'x-bparam': JSON.stringify(bParam),
            'x-gtoken': gToken,
        },
        json: {
            count: limit,
            id: Number.parseInt(tagId),
            type: 'tag_discussion_feed',
        },
    });
    if (tagResponse.code !== 2000) {
        throw new Error(tagResponse.msg);
    }

    const list = parseList(tagResponse.data.list.slice(0, limit), lang, buildId);
    const items = await Promise.all(list.map((item) => parseItem(item)));

    return {
        title: `${tagInfo.name} - Followin`,
        description: tagInfo.description,
        link: `${baseUrl}/${lang}/tag/${tagId}`,
        image: tagInfo.logo,
        language: lang,
        item: items,
    };
}

View on GitHub (pinned to bed535e087)

Solutions

  1. Verify tagId is purely numeric (e.g. 177008) before calling the API, since Number.parseInt(tagId) silently produces NaN for slugs.
  2. Ensure getBuildId() and getGToken() return fresh values — short-cache or re-fetch them if the feed call rejects with an auth-related msg.
  3. Inspect the thrown tagResponse.msg: a token/anti-bot message means regenerate bParam/gToken; a 'not found' message means the tagId is wrong.
  4. Add a retry that re-bootstraps gToken/bParam once before surfacing the error to the user.

Example fix

// before
const gToken = await getGToken();
const bParam = getBParam(lang);
const { data: tagResponse } = await got.post(`${apiUrl}/feed/list/tag`, { ... });
if (tagResponse.code !== 2000) {
    throw new Error(tagResponse.msg);
}

// after
if (!/^\d+$/.test(tagId)) {
    throw new InvalidParameterError(`tagId must be numeric, got: ${tagId}`);
}
let tagResponse;
for (const attempt of [0, 1]) {
    const gToken = await getGToken(attempt === 1);
    const bParam = getBParam(lang);
    ({ data: tagResponse } = await got.post(`${apiUrl}/feed/list/tag`, {
        headers: { 'x-bparam': JSON.stringify(bParam), 'x-gtoken': gToken },
        json: { count: limit, id: Number.parseInt(tagId), type: 'tag_discussion_feed' },
    }));
    if (tagResponse.code === 2000) break;
}
Defensive patterns

Strategy: validation

Validate before calling

if (!/^\d+$/.test(tagId)) {
  throw new InvalidParameterError('tagId must be numeric');
}

Type guard

const isNumericId = (v: string): v is string => /^\d+$/.test(v);

Try / catch

try {
  const { data: tagResponse } = await got.post(`${apiUrl}/feed/list/tag`, { ... });
} catch (e) {
  // tagResponse.code !== 2000 surfaces as a thrown Error with the API msg
  if (/token|auth|gtoken|bparam/i.test((e as Error).message)) {
    // re-bootstrap tokens once and retry
  }
  throw e;
}

Prevention

When it happens

Trigger: Posting to apiUrl/feed/list/tag with an expired or stale gToken/bParam, a non-numeric or deleted tagId (Number.parseInt yields NaN), or when Followin's anti-bot layer flags the request. Also triggered if the tag exists but the feed type 'tag_discussion_feed' yields no data and the API signals it with a non-2000 code.

Common situations: Cached buildId/gToken going stale between the getBuildId/getGToken calls and the feed request; deploying without a reachable Followin frontend so token bootstrap fails silently; passing a tagId copied from a URL that is actually a slug rather than a numeric ID.

Related errors


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