{"record":{"id":"720510f875a5f47d","repo":"jackwener/OpenCLI","slug":"label-cannot-be-empty-720510","errorCode":null,"errorMessage":"${label} cannot be empty","messagePattern":"(.+?) cannot be empty","errorType":"validation","errorClass":"ArgumentError","httpStatus":null,"severity":"error","filePath":"clis/stackoverflow/utils.js","lineNumber":34,"sourceCode":"const UA = 'opencli-stackoverflow (+https://github.com/jackwener/opencli)';\n\n/** Validate `limit` per typed-fail-fast convention (no silent clamp). */\nexport function normalizeLimit(value, defaultValue, maxValue, label = 'limit') {\n    const raw = value ?? defaultValue;\n    const limit = Number(raw);\n    if (!Number.isInteger(limit) || limit <= 0) {\n        throw new ArgumentError(`${label} must be a positive integer`);\n    }\n    if (limit > maxValue) {\n        throw new ArgumentError(`${label} must be <= ${maxValue}`);\n    }\n    return limit;\n}\n\nexport function requireString(value, label) {\n    const raw = String(value ?? '').trim();\n    if (!raw) {\n        throw new ArgumentError(`${label} cannot be empty`);\n    }\n    return raw;\n}\n\n/** Fetch a Stack Exchange API endpoint and return parsed JSON envelope. */\nexport async function seFetch(path, { searchParams } = {}) {\n    const url = new URL(path.startsWith('http') ? path : `${SE_API}${path.startsWith('/') ? '' : '/'}${path}`);\n    if (searchParams) {\n        for (const [k, v] of Object.entries(searchParams)) {\n            if (v == null || v === '') continue;\n            url.searchParams.set(k, String(v));\n        }\n    }\n    if (!url.searchParams.has('site')) url.searchParams.set('site', SE_SITE);\n\n    let resp;\n    try {\n        resp = await fetch(url, {","sourceCodeStart":16,"sourceCodeEnd":52,"githubUrl":"https://github.com/jackwener/OpenCLI/blob/49907e53dc3ade5c223ff0c4c2c2785687cec4e6/clis/stackoverflow/utils.js#L16-L52","documentation":"ArgumentError from requireString in clis/stackoverflow/utils.js when a required string argument is missing, null, or whitespace-only after String() coercion and trim(). Used by commands like `stackoverflow tag` (label 'tag') to reject empty required inputs before any network call.","triggerScenarios":"`stackoverflow tag` with no value, `stackoverflow tag \"   \"`, or a script passing an unset variable so the tag resolves to '' or undefined.","commonSituations":"Shell variables that expand to empty (TAG=\"\"); piping data where the field is blank; forgetting the positional argument; a tag consisting only of whitespace due to copy/paste.","solutions":["Supply a non-empty tag value, e.g. `stackoverflow tag javascript`.","Trim and validate in scripts before calling: if (!tag?.trim()) skip.","Check that the shell variable actually holds a value (`echo \"$TAG\"`)."],"exampleFix":"// before\nstackoverflow tag \"$TAG\"   // TAG empty\n// after\n[ -n \"$TAG\" ] && stackoverflow tag \"$TAG\"","handlingStrategy":"validation","validationCode":"function requireNonEmpty(value, label) {\n  const s = String(value ?? '').trim();\n  if (!s) throw new TypeError(`${label} is required and cannot be empty`);\n  return s;\n}","typeGuard":"function isNonEmptyString(v) { return typeof v === 'string' && v.trim().length > 0; }","tryCatchPattern":"try {\n  await byTag(tag);\n} catch (e) {\n  if (e.name === 'ArgumentError' && e.message.includes('cannot be empty')) {\n    console.error(`usage: stackoverflow tag <non-empty tag>`);\n    process.exitCode = 2;\n    return;\n  }\n  throw e;\n}","preventionTips":["Trim user/config input before passing it as a required argument.","Guard shell variables: `[ -n \"$TAG\" ] || exit 2`.","Make positional required args explicit in scripts rather than relying on expansion.","Watch for whitespace-only values from copy/paste."],"tags":["argument-validation","input-validation","cli"],"backgroundTag":"missing-required-argument","analyzedSha":"49907e53dc3ade5c223ff0c4c2c2785687cec4e6","analyzedAt":"2026-08-29T08:14:47.543Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}