{"record":{"id":"4463e9b5ea1e933d","repo":"DIYgod/RSSHub","slug":"invalid-id-id-allowed-values-are-valid","errorCode":null,"errorMessage":"Invalid id: ${id}. Allowed values are: ${[...validIds].join(', ')}","messagePattern":"Invalid id: (.+?)\\. Allowed values are: (.+?)","errorType":"exception","errorClass":"Error","httpStatus":503,"severity":"warning","filePath":"lib/routes/bandisoft/history.ts","lineNumber":136,"sourceCode":"    },\n    {\n        label: 'Romanian',\n        value: 'ro',\n    },\n    {\n        label: '한국어',\n        value: 'kr',\n    },\n];\n\nexport const handler = async (ctx: Context): Promise<Data> => {\n    const { id = 'bandizip', language = 'en' } = ctx.req.param();\n    const limit = Number(ctx.req.query('limit') ?? '500');\n\n    const validIds = new Set<string>(idOptions.map((option) => option.value));\n\n    if (!validIds.has(id)) {\n        throw new Error(`Invalid id: ${id}. Allowed values are: ${[...validIds].join(', ')}`);\n    }\n\n    const validLanguages = new Set<string>(languageOptions.map((option) => option.value));\n\n    if (!validLanguages.has(language)) {\n        throw new Error(`Invalid language: ${language}. Allowed values are: ${[...validLanguages].join(', ')}`);\n    }\n\n    const baseUrl = `https://${language}.bandisoft.com`;\n    const targetUrl: string = new URL(`${id}/history/`, baseUrl).href;\n\n    const response = await ofetch(targetUrl);\n    const $: CheerioAPI = load(response);\n    const lang = $('html').attr('lang') ?? 'en';\n    const author: string | undefined = $('meta[name=\"author\"]').attr('content');\n\n    const items: DataItem[] = $('div.row')\n        .slice(0, limit)","sourceCodeStart":118,"sourceCodeEnd":154,"githubUrl":"https://github.com/DIYgod/RSSHub/blob/bed535e0879dc71c5aff6f1e7bd1ac21ede40115/lib/routes/bandisoft/history.ts#L118-L154","documentation":"Thrown by the bandisoft history route when the :id path parameter is not one of the values in idOptions (bandizip, bandizip.mac, bandiview, honeycam). It is a whitelist guard built from idOptions, so the error message lists every accepted product id.","triggerScenarios":"Calling /bandisoft/history/:id with an id outside the supported set, e.g. a typo like 'bandizip-mac' (dot vs dash) or a product bandisoft does not have a changelog for.","commonSituations":"User guesses a product slug; outdated doc lists a removed product; case mismatch (ids are lowercase, the check is case-sensitive).","solutions":["Use one of: bandizip, bandizip.mac, bandiview, honeycam (the message lists them).","If adding a new Bandisoft product, append it to idOptions so both validation and docs stay consistent."],"exampleFix":null,"handlingStrategy":"validation","validationCode":"const VALID_IDS = new Set(idOptions.map((o) => o.value));\nif (!VALID_IDS.has(id)) {\n    throw new InvalidParameterError(`Invalid id: ${id}. Allowed: ${[...VALID_IDS].join(', ')}`);\n}","typeGuard":"function isBandisoftId(v: string): boolean {\n    return idOptions.some((o) => o.value === v);\n}","tryCatchPattern":null,"preventionTips":["Expose the allow-list in the route's parameters.options so RSSHub surfaces valid values in docs/UI.","Use InvalidParameterError for whitelist failures."],"tags":["bandisoft","input-validation","route-parameter","whitelist"],"backgroundTag":null,"analyzedSha":"bed535e0879dc71c5aff6f1e7bd1ac21ede40115","analyzedAt":"2026-08-12T19:29:35.364Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}