{"record":{"id":"80556ec8e6e46b41","repo":"jackwener/OpenCLI","slug":"argument-80556e","errorCode":"ARGUMENT","errorMessage":"\"${name}\" must be either \"yes\" or \"no\".","messagePattern":"\"(.+?)\" must be either \"yes\" or \"no\"\\.","errorType":"validation","errorClass":"CliError","httpStatus":null,"severity":"error","filePath":"clis/paperreview/utils.js","lineNumber":37,"sourceCode":"            return detail;\n        if (message)\n            return message;\n        if (error)\n            return error;\n    }\n    const text = trimOrEmpty(payload);\n    return text || fallback;\n}\nexport function buildReviewUrl(token) {\n    return `${PAPERREVIEW_BASE_URL}/review?token=${encodeURIComponent(token)}`;\n}\nexport function parseYesNo(value, name) {\n    const normalized = trimOrEmpty(value).toLowerCase();\n    if (normalized === 'yes')\n        return true;\n    if (normalized === 'no')\n        return false;\n    throw new CliError('ARGUMENT', `\"${name}\" must be either \"yes\" or \"no\".`);\n}\nexport function normalizeVenue(value) {\n    return trimOrEmpty(value);\n}\nexport function validateHelpfulness(value) {\n    const numeric = Number(value);\n    if (!Number.isInteger(numeric) || numeric < 1 || numeric > 5) {\n        throw new CliError('ARGUMENT', '\"helpfulness\" must be an integer from 1 to 5.');\n    }\n    return numeric;\n}\nexport async function readPdfFile(inputPath) {\n    const rawPath = trimOrEmpty(inputPath);\n    if (!rawPath) {\n        throw new CliError('ARGUMENT', 'A PDF path is required.', 'Provide a local PDF file path');\n    }\n    const resolvedPath = path.resolve(rawPath);\n    const fileName = path.basename(resolvedPath);","sourceCodeStart":19,"sourceCodeEnd":55,"githubUrl":"https://github.com/jackwener/OpenCLI/blob/49907e53dc3ade5c223ff0c4c2c2785687cec4e6/clis/paperreview/utils.js#L19-L55","documentation":"parseYesNo converts CLI yes/no flags into booleans and throws CliError (code ARGUMENT) for any other value. Flags like --critical-error, --actionable-suggestions must literally be \"yes\" or \"no\" (case-insensitive). This keeps tri-state flags strict rather than guessing at truthy strings.","triggerScenarios":"Passing --critical-error true/false, 1/0, y/n, or any value other than yes/no (case-insensitive after trim/lowercase).","commonSituations":"Users accustomed to boolean CLI conventions passing \"true\"; scripts interpolating 0/1 from config files; locale-mixed casing is fine (lowercased) but typos like \"yes.\" fail.","solutions":["Pass exactly yes or no (any casing): --critical-error yes.","Replace true/false or 1/0 with yes/no in scripts.","Normalize values in wrapper scripts before forwarding to the CLI."],"exampleFix":"// before\ncli feedback --token t --critical-error true\n// after\ncli feedback --token t --critical-error yes","handlingStrategy":"validation","validationCode":"function toYesNo(v) {\n  const n = String(v ?? '').trim().toLowerCase();\n  if (n !== 'yes' && n !== 'no') throw new Error(`\"${v}\" must be yes or no`);\n  return n;\n}","typeGuard":"function isYesNo(v) {\n  const n = String(v ?? '').trim().toLowerCase();\n  return n === 'yes' || n === 'no';\n}","tryCatchPattern":"try {\n  await cli.feedback({ 'critical-error': 'true' });\n} catch (err) {\n  if (err.code === 'ARGUMENT' && /yes.*no/.test(err.message)) console.error('Use --critical-error yes|no (not true/false)');\n  else throw err;\n}","preventionTips":["Always pass literal yes/no, never true/false or 1/0.","Normalize booleans in wrapper scripts before forwarding.","Casing is flexible (YES/No fine); spelling must be exact."],"tags":["cli","validation","argument-parsing"],"backgroundTag":"invalid-argument-value","analyzedSha":"49907e53dc3ade5c223ff0c4c2c2785687cec4e6","analyzedAt":"2026-08-29T08:14:47.543Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}