{"record":{"id":"52401633691648eb","repo":"DIYgod/RSSHub","slug":"invalid-user-524016","errorCode":null,"errorMessage":"Invalid user","messagePattern":"Invalid user","errorType":"validation","errorClass":"InvalidParameterError","httpStatus":503,"severity":"error","filePath":"lib/routes/substack/subscribe.ts","lineNumber":32,"sourceCode":"    parameters: { user: 'Username of the Substack' },\n    features: {\n        requireConfig: false,\n        requirePuppeteer: false,\n        antiCrawler: false,\n        supportBT: false,\n        supportPodcast: false,\n        supportScihub: false,\n    },\n    name: 'Substack Subscription',\n    maintainers: ['pseudoyu'],\n    handler,\n};\n\nasync function handler(ctx) {\n    const user = ctx.req.param('user');\n\n    if (!isValidHost(user)) {\n        throw new InvalidParameterError('Invalid user');\n    }\n\n    const response = await ofetch(`https://${user}.substack.com/feed`);\n    const feed = await parser.parseString(response);\n\n    return {\n        title: feed.title ?? 'Substack',\n        description: feed.description ?? `${user}'s Substack`,\n        link: feed.link ?? `https://${user}.substack.com`,\n        image: feed.image?.url ?? '',\n        item: feed.items.map((item) => ({\n            title: item.title ?? 'Untitled',\n            description: item['content:encoded'] ?? item.content ?? '',\n            link: item.link ?? '',\n            pubDate: item.pubDate ? parseDate(item.pubDate) : undefined,\n            guid: item.guid ?? '',\n            author: item.creator ?? user,\n        })),","sourceCodeStart":14,"sourceCodeEnd":50,"githubUrl":"https://github.com/DIYgod/RSSHub/blob/bed535e0879dc71c5aff6f1e7bd1ac21ede40115/lib/routes/substack/subscribe.ts#L14-L50","documentation":"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.","triggerScenarios":"/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.","commonSituations":"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.","solutions":["Pass only the bare substack subdomain — the part before '.substack.com' (e.g. 'mangoread', not 'https://mangoread.substack.com').","Strip leading/trailing hyphens and whitespace; ensure length is <= 63 and contains only letters, digits, and internal hyphens.","For custom-domain Substackes this route cannot be used — subscribe via the publication's own RSS feed URL directly."],"exampleFix":"// before\nGET /substack/subscribe/mangoread.substack.com\n// after\nGET /substack/subscribe/mangoread","handlingStrategy":"validation","validationCode":"import { isValidHost } from '@/utils/valid-host';\n\n// Run the same check the route runs, before constructing the URL.\nfunction isValidSubstackUser(user: string): boolean {\n  return isValidHost(user);\n}","typeGuard":"import { isValidHost } from '@/utils/valid-host';\n\nfunction isSubstackSubdomain(user: string): user is string {\n  return typeof user === 'string'\n    && user.length > 0\n    && user.length <= 63\n    && !user.startsWith('-')\n    && !user.endsWith('-')\n    && /^[\\da-z-]+$/i.test(user)\n    && isValidHost(user);\n}","tryCatchPattern":null,"preventionTips":["Pass only the subdomain part before '.substack.com' — no protocol, no dots, no path.","This route cannot serve custom-domain Substackes; use the publication's own RSS URL for those.","Trim leading/trailing whitespace and hyphens before submitting."],"tags":["invalid-parameter","user-input","hostname-validation","substack"],"backgroundTag":null,"analyzedSha":"bed535e0879dc71c5aff6f1e7bd1ac21ede40115","analyzedAt":"2026-08-12T19:29:35.364Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}