{"record":{"id":"46afe484f55b8746","repo":"jackwener/OpenCLI","slug":"all-must-be-a-boolean","errorCode":null,"errorMessage":"--all must be a boolean","messagePattern":"--all must be a boolean","errorType":"validation","errorClass":"ArgumentError","httpStatus":null,"severity":"error","filePath":"clis/xiaoyuzhou/history.js","lineNumber":150,"sourceCode":"        progressById.set(eid, {\n            progressSec,\n            playedAt: optionalIsoTime(row.playedAt, `playedAt in row ${index + 1}`),\n        });\n    }\n    for (const episode of episodes) {\n        if (!progressById.has(episode.eid)) {\n            throw new CommandExecutionError(\n                `Xiaoyuzhou playback progress omitted requested eid ${episode.eid}; the history join is incomplete`,\n            );\n        }\n    }\n    return progressById;\n}\n\nasync function fetchHistory(args = {}) {\n    const fetchAll = args.all ?? false;\n    if (typeof fetchAll !== 'boolean') {\n        throw new ArgumentError('--all must be a boolean');\n    }\n    const limit = fetchAll ? null : positiveInteger(args.limit ?? DEFAULT_LIMIT, 'limit', MAX_LIMIT);\n    const maxPages = positiveInteger(args['max-pages'] ?? DEFAULT_MAX_PAGES, 'max-pages', HARD_MAX_PAGES);\n    let credentials = loadXiaoyuzhouCredentials();\n    const seenEpisodeIds = new Set();\n    const seenCursors = new Set();\n    const rows = [];\n    let loadMoreKey = null;\n    let exhausted = false;\n\n    for (let pageNumber = 1; pageNumber <= maxPages; pageNumber += 1) {\n        const historyResponse = await requestXiaoyuzhouJson(HISTORY_ENDPOINT, {\n            method: 'POST',\n            body: loadMoreKey === null ? {} : { loadMoreKey },\n            credentials,\n        });\n        credentials = historyResponse.credentials;\n        const page = parseHistoryPage(historyResponse);","sourceCodeStart":132,"sourceCodeEnd":168,"githubUrl":"https://github.com/jackwener/OpenCLI/blob/49907e53dc3ade5c223ff0c4c2c2785687cec4e6/clis/xiaoyuzhou/history.js#L132-L168","documentation":"fetchHistory expects args.all to be a strict boolean (defaulting to false). Passing any other type makes the --all flag's intent ambiguous, so an ArgumentError is thrown before any network call.","triggerScenarios":"Calling fetchHistory({ all: 'true' }), fetchHistory({ all: 1 }), or similar truthy non-boolean values from CLI-parsed options or hand-assembled argument objects.","commonSituations":"CLI frameworks delivering options as strings ('true'/'false'); env-var-driven config where everything is a string; migrating code that previously relied on truthiness; YAML/JSON config with quoted versus unquoted booleans.","solutions":["Pass a real boolean: fetchHistory({ all: true }).","Coerce string options with a strict parser (only 'true'/'false' accepted) before calling fetchHistory.","If using a CLI parser, enable automatic boolean typing (e.g. commander's .option('--all') or yargs' boolean: ['all']).","Audit config-loading code so all/limit/max-pages arrive with documented types."],"exampleFix":"// before\nawait fetchHistory({ all: process.env.HISTORY_ALL });\n// after\nconst all = process.env.HISTORY_ALL === 'true' ? true\n  : process.env.HISTORY_ALL === 'false' ? false\n  : undefined;\nawait fetchHistory({ all });","handlingStrategy":"type-guard","validationCode":"if (args.all !== undefined && typeof args.all !== 'boolean') {\n  throw new TypeError('all must be a boolean');\n}","typeGuard":"const isBoolean = (v) => typeof v === 'boolean';\nconst parseBoolFlag = (v) => v === undefined ? undefined\n  : v === 'true' ? true : v === 'false' ? false : null;","tryCatchPattern":"try {\n  await fetchHistory(args);\n} catch (e) {\n  if (e instanceof ArgumentError && e.message.includes('--all')) {\n    console.error('Pass --all as a true/false boolean');\n  } else throw e;\n}","preventionTips":["Use a CLI parser with boolean option typing.","Strictly coerce string flags ('true'/'false') before calling.","Document expected argument types for fetchHistory."],"tags":["argument-validation","types","cli","developer-error"],"backgroundTag":"invalid-argument-type","analyzedSha":"49907e53dc3ade5c223ff0c4c2c2785687cec4e6","analyzedAt":"2026-08-29T08:14:47.543Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}