{"record":{"id":"23f4e92275221845","repo":"jackwener/OpenCLI","slug":"xianyu-publish-label-must-be-a-positive-price","errorCode":null,"errorMessage":"xianyu publish ${label} must be a positive price","messagePattern":"xianyu publish (.+?) must be a positive price","errorType":"validation","errorClass":"ArgumentError","httpStatus":null,"severity":"error","filePath":"clis/xianyu/publish.js","lineNumber":44,"sourceCode":"function requireText(value, label) {\n    const text = String(value ?? '').replace(/\\s+/g, ' ').trim();\n    if (!text) {\n        throw new ArgumentError(`xianyu publish ${label} cannot be empty`);\n    }\n    return text;\n}\n\nfunction parsePositivePrice(value, label) {\n    if (value == null || String(value).trim() === '') {\n        return null;\n    }\n    const text = String(value).trim();\n    if (!/^\\d+(?:\\.\\d{1,2})?$/.test(text)) {\n        throw new ArgumentError(`xianyu publish ${label} must be a positive price with at most 2 decimals`);\n    }\n    const price = Number(text);\n    if (!Number.isFinite(price) || price <= 0) {\n        throw new ArgumentError(`xianyu publish ${label} must be a positive price`);\n    }\n    return text;\n}\n\nfunction validateCondition(value) {\n    const condition = requireText(value, 'condition');\n    if (!CONDITION_CHOICES.includes(condition)) {\n        throw new ArgumentError(`xianyu publish condition must be one of: ${CONDITION_CHOICES.join(', ')}`);\n    }\n    return condition;\n}\n\nfunction validateImagePaths(raw) {\n    if (!raw) return [];\n    const paths = String(raw).split(',').map((item) => item.trim()).filter(Boolean);\n    if (paths.length === 0) return [];\n    if (paths.length > MAX_IMAGES) {\n        throw new ArgumentError(`xianyu publish images supports at most ${MAX_IMAGES} files`);","sourceCodeStart":26,"sourceCodeEnd":62,"githubUrl":"https://github.com/jackwener/OpenCLI/blob/49907e53dc3ade5c223ff0c4c2c2785687cec4e6/clis/xianyu/publish.js#L26-L62","documentation":"parsePositivePrice validates the xianyu publish price and throws ArgumentError when the value, though formatted as a decimal string, is not strictly positive (e.g. zero) or not finite. The regex already limits input to digits with at most 2 decimals, so this branch fires when the numeric value fails the > 0 check. The library throws it to guarantee a real positive price before submitting the listing.","triggerScenarios":"Calling normalizePublishArgs (or the price helper) with kwargs.price = '0', '0.00', or '0.0' — passes the decimal regex but fails price <= 0.","commonSituations":"Placeholder price of 0 ('decide later'), templated scripts with unfilled price variables defaulting to 0, or spreadsheet imports where an empty price cell is coerced to '0'.","solutions":["Pass a price greater than 0 with at most 2 decimals, e.g. price: '29.90'","Add a caller-side check that Number(price) > 0 before invoking publish","If price is optional in your flow, omit it rather than passing '0'"],"exampleFix":"// before\nawait publish({ title: 'Phone', price: '0' });\n// after\nawait publish({ title: 'Phone', price: '29.90' });","handlingStrategy":"validation","validationCode":"function isValidPrice(p) {\n  return typeof p === 'string' && /^\\d+(?:\\.\\d{1,2})?$/.test(p.trim()) && Number(p) > 0;\n}\nif (!isValidPrice(price)) throw new Error(`price must be > 0: got ${price}`);","typeGuard":"function isPositivePrice(v) {\n  return typeof v === 'string' && /^\\d+(?:\\.\\d{1,2})?$/.test(v.trim()) && Number(v) > 0;\n}","tryCatchPattern":"try {\n  await publish({ price });\n} catch (e) {\n  if (e instanceof ArgumentError && /must be a positive price/.test(e.message)) {\n    console.error(`Bad price \"${price}\": use a number > 0 with max 2 decimals`);\n  } else throw e;\n}","preventionTips":["Validate price with a regex + Number() > 0 check before calling publish","Never pass 0 as a placeholder; omit optional fields instead","Keep prices as strings from CLI/JSON to avoid float formatting surprises"],"tags":["validation","argument-error","price"],"backgroundTag":"invalid-price-value","analyzedSha":"49907e53dc3ade5c223ff0c4c2c2785687cec4e6","analyzedAt":"2026-08-29T08:14:47.543Z","schemaVersion":2},"datasetVersion":"2026-08-29T17:17:51.833Z"}