DIYgod/RSSHub · error · Error

${response.msg}

Error message

${response.msg}

What it means

Thrown when the Followin (followin.io) recommended feed API at `${apiUrl}/feed/list/recommended` returns a response with `code !== 2000` (the success code). The route authenticates with a computed `x-bparam` (browser fingerprint) and `x-gtoken`, then posts with a category_id and count. Any non-2000 code causes the upstream `msg` field to be rethrown verbatim. This is a passthrough of API-level errors.

Source

Thrown at lib/routes/followin/index.ts:80

async function handler(ctx) {
    const { categoryId = '1', lang = 'en' } = ctx.req.param();
    const { limit = 20 } = ctx.req.query();
    const gToken = await getGToken();
    const bParam = getBParam(lang);

    const { data: response } = await got.post(`${apiUrl}/feed/list/recommended`, {
        headers: {
            'x-bparam': JSON.stringify(bParam),
            'x-gtoken': gToken,
        },
        json: {
            category_id: Number.parseInt(categoryId),
            count: Number.parseInt(limit),
        },
    });
    if (response.code !== 2000) {
        throw new Error(response.msg);
    }

    const buildId = await getBuildId();

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

    return {
        title: 'Followin',
        link: 'https://followin.io',
        image: favicon,
        item: items,
    };
}

View on GitHub (pinned to bed535e087)

Solutions

  1. Verify the categoryId is one of the documented values: 1, 3, 5, 6, 8, 9, 11, 13, or 14.
  2. Check whether the getGToken and getBParam utilities in utils.ts still produce valid tokens by testing against the Followin API directly.
  3. If the error is intermittent, reduce request frequency to avoid rate-limiting.
  4. Log `response` to inspect the full error code and message for diagnosis.

Example fix

// before
if (response.code !== 2000) {
    throw new Error(response.msg);
}

// after — include the code and categoryId for faster diagnosis
if (response.code !== 2000) {
    throw new Error(`Followin feed/list/recommended error (code=${response.code}, categoryId=${categoryId}): ${response.msg}`);
}
Defensive patterns

Strategy: try-catch

Validate before calling

const VALID_CATEGORY_IDS = new Set(['1', '3', '5', '6', '8', '9', '11', '13', '14']);

function validateCategoryId(id: string | undefined): string {
    const resolved = id ?? '1';
    if (!VALID_CATEGORY_IDS.has(resolved)) {
        throw new InvalidParameterError(`Invalid categoryId: ${id}. Valid: 1, 3, 5, 6, 8, 9, 11, 13, 14`);
    }
    return resolved;
}

Type guard

interface FollowinSuccessResponse {
    code: 2000;
    data: { list: unknown[] };
}

function isFollowinSuccess(res: unknown): res is FollowinSuccessResponse {
    return typeof res === 'object' && res !== null &&
        (res as any).code === 2000;
}

Try / catch

try {
    const { data: response } = await got.post(url, options);
    if (response.code !== 2000) {
        throw new Error(`Followin API error (code=${response.code}): ${response.msg}`);
    }
} catch (e) {
    if (e instanceof Error && e.message.includes('Followin API error')) {
        // API-level rejection — likely token or categoryId issue
    }
    throw e;
}

Prevention

When it happens

Trigger: An invalid or unsupported categoryId is passed (the API returns an error code). The x-gtoken or x-bparam computation is stale or rejected by Followin's anti-bot system. The API rate-limits the RSSHub instance. Followin changed their success code or API contract.

Common situations: User passes a categoryId not in the documented list (1, 3, 5, 6, 8, 9, 11, 13, 14). Followin updates their anti-bot token generation, invalidating getGToken/getBParam. Rate-limiting after frequent polling. The API endpoint path or version changed.

Related errors


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