{"record":{"id":"eaf69230258f525a","repo":"jackwener/OpenCLI","slug":"hotel-id-must-be-a-positive-integer-got-json-st","errorCode":null,"errorMessage":"hotel id must be a positive integer, got ${JSON.stringify(raw)}","messagePattern":"hotel id must be a positive integer, got (.+?)","errorType":"validation","errorClass":"ArgumentError","httpStatus":null,"severity":"error","filePath":"clis/ctrip/utils.js","lineNumber":608,"sourceCode":"      const result = detect();\n      if (result) { observer.disconnect(); resolve(result); }\n    });\n    observer.observe(document.documentElement, { childList: true, subtree: true });\n    setTimeout(() => { observer.disconnect(); resolve('timeout'); }, 10000);\n  })\n`;\n\n/* ------------------------- hotel detail (browser SSR) ------------------------- */\n\n/** Validate a numeric Ctrip hotel id (returned by `ctrip hotel-suggest`). */\nexport function parseHotelId(raw) {\n    if (raw === undefined || raw === null || String(raw).trim() === '') {\n        throw new ArgumentError('hotel id is required (numeric id from `ctrip hotel-suggest`, e.g. 375539)');\n    }\n    try {\n        return parseStrictPositiveInteger('id', raw);\n    } catch {\n        throw new ArgumentError(`hotel id must be a positive integer, got ${JSON.stringify(raw)}`);\n    }\n}\n\nexport function buildHotelDetailUrl(hotelId) {\n    return `https://hotels.ctrip.com/hotels/detail/?hotelid=${hotelId}`;\n}\n\n/**\n * Browser-context IIFE that projects the single-hotel profile from\n * `__NEXT_DATA__.props.pageProps.hotelDetailResponse`. Rating sub-scores, hot\n * facilities, and the check-in/out policy are each joined into one string so the\n * profile stays a single flat row. Returns `null` when the SSR block is absent,\n * so the caller raises a typed error instead of surfacing blanks. Room-level\n * nightly prices load via a post-SSR XHR into hashed CSS-module cards and are out\n * of scope here, the same way `flight`'s post-load price XHR is.\n */\nexport function buildHotelDetailExtractJs() {\n    return `","sourceCodeStart":590,"sourceCodeEnd":626,"githubUrl":"https://github.com/jackwener/OpenCLI/blob/49907e53dc3ade5c223ff0c4c2c2785687cec4e6/clis/ctrip/utils.js#L590-L626","documentation":"After the presence check, parseHotelId delegates to parseStrictPositiveInteger('id', raw); any failure (non-numeric text, decimals, zero, negatives, junk-suffixed numbers) is rethrown as ArgumentError 'hotel id must be a positive integer'. The ID is interpolated directly into the hotel detail URL, so it must be a clean positive integer.","triggerScenarios":"Passing a hotel id like 'abc', '375539.5', '0', '-1', 'id:375539', or a value with trailing spaces/invisible characters to the hotel-detail command.","commonSituations":"Pasting IDs with formatting from HTML/URLs (e.g. 'hotelid=375539&'), mixing up city IDs with hotel IDs, or hand-typing IDs with typos.","solutions":["Re-run `ctrip hotel-suggest` and copy the exact numeric hotel id.","Strip non-digit characters and trim whitespace before passing the value.","Use a strictly positive integer (>= 1); decimals, zero and negatives are rejected."],"exampleFix":"// before\nctrip hotel-detail --id \"hotelid=375539\"\n// after\nctrip hotel-detail --id 375539","handlingStrategy":"validation","validationCode":"const n = Number(String(raw).trim());\nif (!Number.isInteger(n) || n < 1) throw new Error('hotel id must be a positive integer, got ' + raw);","typeGuard":"const isPositiveInt = (v) => typeof v === 'number' ? Number.isInteger(v) && v > 0 : /^\\d+$/.test(String(v).trim());","tryCatchPattern":"try {\n  const id = parseHotelId(raw);\n} catch (e) {\n  if (e instanceof ArgumentError && e.message.includes('positive integer')) {\n    const digits = String(raw).replace(/\\D/g, '');\n    if (digits) return parseHotelId(digits);\n  }\n  throw e;\n}","preventionTips":["Extract the bare numeric id from URLs/HTML (hotelid=(\\d+)) before passing it.","Do not confuse hotel IDs with city IDs.","Validate with /^\\d+$/ in scripts that forward IDs."],"tags":["cli","validation","argument-error","integer-validation"],"backgroundTag":"invalid-cli-argument","analyzedSha":"49907e53dc3ade5c223ff0c4c2c2785687cec4e6","analyzedAt":"2026-08-29T08:14:47.543Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}