{"record":{"id":"fc153128f23bd014","repo":"DIYgod/RSSHub","slug":"id-catalogid-list","errorCode":null,"errorMessage":"id 为 ${catalogId} 的 List 不存在","messagePattern":"id 为 (.+?) 的 List 不存在","errorType":"validation","errorClass":"InvalidParameterError","httpStatus":null,"severity":"error","filePath":"lib/routes/medium/list.ts","lineNumber":45,"sourceCode":"::: warning\nTo access private lists, only self-hosting is supported.\n:::`,\n};\n\nasync function handler(ctx) {\n    const user = ctx.req.param('user');\n    const catalogId = ctx.req.param('catalogId');\n\n    const cookie = config.medium.cookies[user];\n\n    const catalog = await getUserCatalogMainContentQuery(user, catalogId, cookie);\n    ctx.set('json', catalog);\n\n    if (catalog && catalog.__typename === 'Forbidden') {\n        throw new ConfigNotFoundError(`无权访问 id 为 ${catalogId} 的 List（可能是未设置 Cookie 或 Cookie 已过期）`);\n    }\n    if (!catalog || !catalog.itemsConnection) {\n        throw new InvalidParameterError(`id 为 ${catalogId} 的 List 不存在`);\n    }\n\n    const name = catalog.name;\n    const urls = catalog.itemsConnection.items.map((item) => item.entity.mediumUrl);\n\n    const parsedArticles = await Promise.all(urls.map((url) => parseArticle(ctx, url)));\n\n    return {\n        title: `List: ${name}`,\n        link: `https://medium.com/@${user}/list/${catalogId}`,\n        item: parsedArticles,\n    };\n}\n","sourceCodeStart":27,"sourceCodeEnd":59,"githubUrl":"https://github.com/DIYgod/RSSHub/blob/bed535e0879dc71c5aff6f1e7bd1ac21ede40115/lib/routes/medium/list.ts#L27-L59","documentation":"InvalidParameterError thrown when the Medium catalog (list) API returns no usable data — the catalog object is null, or it lacks an itemsConnection. This means a list with the given catalogId does not exist or is empty for that user.","triggerScenarios":"getUserCatalogMainContentQuery resolves to null, or to an object without itemsConnection (and __typename is not 'Forbidden'). Medium's API could not find a list matching the catalogId.","commonSituations":"Wrong catalogId in the URL; list was deleted by its owner; list ID copied incompletely; user segment refers to a different account that doesn't own the list.","solutions":["Open the list on medium.com in a browser and copy the catalogId from the URL exactly.","Confirm the :user segment matches the list owner.","If the list was deleted, use the current list ID.","Distinguish this from 367: if you get Forbidden, fix the cookie first."],"exampleFix":"// before\n// /medium/list/johndoe/abc123-wrong\n\n// after\n// /medium/list/johndoe/correct-uuid-from-url","handlingStrategy":"validation","validationCode":"const catalogId = ctx.req.param('catalogId');\nif (!catalogId || !/^[a-zA-Z0-9_-]+$/.test(catalogId)) {\n    throw new InvalidParameterError('catalogId must be a non-empty alphanumeric token');\n}","typeGuard":"function isCatalogId(value: unknown): value is string {\n    return typeof value === 'string' && /^[a-zA-Z0-9_-]+$/.test(value);\n}","tryCatchPattern":null,"preventionTips":["Copy catalogId verbatim from the medium.com list URL.","Validate the format at the route boundary.","Distinguish 404-style (this) from Forbidden (367) in user messaging."],"tags":["medium","validation","user-input","not-found"],"backgroundTag":null,"analyzedSha":"bed535e0879dc71c5aff6f1e7bd1ac21ede40115","analyzedAt":"2026-08-12T19:29:35.364Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}