{"record":{"id":"e8efbaba753b6dfe","repo":"jackwener/OpenCLI","slug":"shot-must-be-a-numeric-id-or-dribbble-com-shots-ur","errorCode":null,"errorMessage":"shot must be a numeric id or dribbble.com/shots URL","messagePattern":"shot must be a numeric id or dribbble\\.com/shots URL","errorType":"validation","errorClass":"ArgumentError","httpStatus":null,"severity":"error","filePath":"clis/dribbble/utils.js","lineNumber":57,"sourceCode":"export function requireDesigner(value) {\n    const designer = String(value ?? '').trim();\n    if (!designer) throw new ArgumentError('designer is required (for example: halolab)');\n    if (!/^[A-Za-z0-9_-]{1,100}$/.test(designer)) {\n        throw new ArgumentError('designer must be a Dribbble username or profile slug');\n    }\n    return designer;\n}\n\nexport function requireShotTarget(value) {\n    const target = String(value ?? '').trim();\n    if (!target) throw new ArgumentError('shot is required (numeric id or dribbble.com/shots URL)');\n    if (/^\\d+$/.test(target)) return target;\n\n    let url;\n    try {\n        url = new URL(target);\n    } catch {\n        throw new ArgumentError('shot must be a numeric id or dribbble.com/shots URL');\n    }\n    if (!/(^|\\.)dribbble\\.com$/i.test(url.hostname)) {\n        throw new ArgumentError('shot URL must use dribbble.com');\n    }\n    const match = url.pathname.match(/^\\/shots\\/(\\d+)(?:-|\\/|$)/);\n    if (!match) throw new ArgumentError('shot URL must match dribbble.com/shots/<id>');\n    return match[1];\n}\n\nexport function requireRows(payload, command) {\n    if (!payload || typeof payload !== 'object') {\n        throw new CommandExecutionError(`${command} returned an unreadable browser payload`);\n    }\n    if (payload.empty) {\n        throw new EmptyResultError(command, payload.reason || `${command} returned no results`);\n    }\n    if (!payload.ok) {\n        const reason = payload.reason ? `: ${payload.reason}` : '';","sourceCodeStart":39,"sourceCodeEnd":75,"githubUrl":"https://github.com/jackwener/OpenCLI/blob/49907e53dc3ade5c223ff0c4c2c2785687cec4e6/clis/dribbble/utils.js#L39-L75","documentation":"requireShotTarget first accepts pure numeric ids, then attempts to parse the value as a URL with the URL constructor. When parsing fails (no scheme, invalid characters, etc.) it throws this ArgumentError because the value is neither a numeric id nor a parseable URL.","triggerScenarios":"Passing values like 'dribbble.com/shots/123' (no protocol), 'http://shot 123', 'shot/123456', or any free-form text that is not all digits and not an absolute URL.","commonSituations":"Copy-pasting a URL from a browser address bar but dropping the 'https://' prefix, users typing shorthand references, or CSV fields containing mixed id/URL values where some are malformed.","solutions":["Include the full scheme when passing a URL: 'https://dribbble.com/shots/1234567'.","Pass just the numeric id if you have it — it avoids URL parsing entirely.","Pre-validate: if the value is not /^\\d+$/, ensure it starts with http:// or https:// before calling."],"exampleFix":"// before\ncli.shot({ shot: 'dribbble.com/shots/1234567' }) // URL parse fails\n\n// after\nlet shot = 'dribbble.com/shots/1234567';\nif (!/^\\d+$/.test(shot) && !/^https?:\\/\\//.test(shot)) shot = 'https://' + shot;\ncli.shot({ shot });","handlingStrategy":"validation","validationCode":"function normalizeShotTarget(v) {\n  const s = String(v ?? '').trim();\n  if (/^\\d+$/.test(s)) return s;\n  if (!/^https?:\\/\\//i.test(s)) return 'https://' + s.replace(/^\\/+/, '');\n  return s;\n}","typeGuard":"function isNumericShotId(v) {\n  return typeof v === 'string' && /^\\d+$/.test(v.trim());\n}","tryCatchPattern":"try {\n  const result = command({ shot });\n} catch (e) {\n  if (e instanceof ArgumentError && /numeric id or dribbble\\.com\\/shots URL/.test(e.message)) {\n    console.error(`'${shot}' is neither a numeric id nor a full URL; use https://dribbble.com/shots/<id>`);\n    return;\n  }\n  throw e;\n}","preventionTips":["Prefer passing numeric ids; they sidestep all URL parsing pitfalls.","Always include the https:// scheme when passing URLs copied from a browser.","Sanitize pasted input by adding the scheme when missing before calling the library."],"tags":["argument-validation","url-parsing","format-validation"],"backgroundTag":"invalid-url-format","analyzedSha":"49907e53dc3ade5c223ff0c4c2c2785687cec4e6","analyzedAt":"2026-08-29T08:14:47.543Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}