DIYgod/RSSHub · error · InvalidParameterError

Invalid user

Error message

Invalid user

What it means

Thrown by substack/subscribe.ts:32 as an InvalidParameterError when isValidHost(user) returns false. isValidHost (lib/utils/valid-host.ts) only checks the subdomain SHAPE via /^\dA-Z(?:[\dA-Z-]{0,61}[\dA-Z])?$/i — it does NOT verify the Substack exists. It rejects empty values, values starting/ending with '-', values over 63 chars, and any value containing '.', '_', or other non-hostname characters. Existence of the publication is checked separately by the later ofetch to https://<user>.substack.com/feed.

Source

Thrown at lib/routes/substack/subscribe.ts:32

    parameters: { user: 'Username of the Substack' },
    features: {
        requireConfig: false,
        requirePuppeteer: false,
        antiCrawler: false,
        supportBT: false,
        supportPodcast: false,
        supportScihub: false,
    },
    name: 'Substack Subscription',
    maintainers: ['pseudoyu'],
    handler,
};

async function handler(ctx) {
    const user = ctx.req.param('user');

    if (!isValidHost(user)) {
        throw new InvalidParameterError('Invalid user');
    }

    const response = await ofetch(`https://${user}.substack.com/feed`);
    const feed = await parser.parseString(response);

    return {
        title: feed.title ?? 'Substack',
        description: feed.description ?? `${user}'s Substack`,
        link: feed.link ?? `https://${user}.substack.com`,
        image: feed.image?.url ?? '',
        item: feed.items.map((item) => ({
            title: item.title ?? 'Untitled',
            description: item['content:encoded'] ?? item.content ?? '',
            link: item.link ?? '',
            pubDate: item.pubDate ? parseDate(item.pubDate) : undefined,
            guid: item.guid ?? '',
            author: item.creator ?? user,
        })),

View on GitHub (pinned to bed535e087)

Solutions

  1. Pass only the bare substack subdomain — the part before '.substack.com' (e.g. 'mangoread', not 'https://mangoread.substack.com').
  2. Strip leading/trailing hyphens and whitespace; ensure length is <= 63 and contains only letters, digits, and internal hyphens.
  3. For custom-domain Substackes this route cannot be used — subscribe via the publication's own RSS feed URL directly.

Example fix

// before
GET /substack/subscribe/mangoread.substack.com
// after
GET /substack/subscribe/mangoread
Defensive patterns

Strategy: validation

Validate before calling

import { isValidHost } from '@/utils/valid-host';

// Run the same check the route runs, before constructing the URL.
function isValidSubstackUser(user: string): boolean {
  return isValidHost(user);
}

Type guard

import { isValidHost } from '@/utils/valid-host';

function isSubstackSubdomain(user: string): user is string {
  return typeof user === 'string'
    && user.length > 0
    && user.length <= 63
    && !user.startsWith('-')
    && !user.endsWith('-')
    && /^[\da-z-]+$/i.test(user)
    && isValidHost(user);
}

Prevention

When it happens

Trigger: /substack/subscribe/<user> where user has a dot (custom-domain Substackes), underscore, leading/trailing hyphen, is empty, or exceeds 63 chars. Also fires when the user passes a full URL, an email, or includes a trailing slash/space.

Common situations: Substack publication on a custom domain (e.g. newsletter.example.com) which does not fit the <user>.substack.com model; user pastes the full Substack URL or an email address as the param; trailing whitespace or slash from a copy-paste.

Related errors


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