{"record":{"id":"5315394658803cdd","repo":"jackwener/OpenCLI","slug":"shot-url-must-match-dribbble-com-shots-id","errorCode":null,"errorMessage":"shot URL must match dribbble.com/shots/<id>","messagePattern":"shot URL must match dribbble\\.com/shots/<id>","errorType":"validation","errorClass":"ArgumentError","httpStatus":null,"severity":"error","filePath":"clis/dribbble/utils.js","lineNumber":63,"sourceCode":"    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}` : '';\n        throw new CommandExecutionError(`${command} selector drift${reason}`);\n    }\n    if (!Array.isArray(payload.rows)) {\n        throw new CommandExecutionError(`${command} returned a malformed rows payload`);\n    }\n    if (payload.rows.length === 0) {","sourceCodeStart":45,"sourceCodeEnd":81,"githubUrl":"https://github.com/jackwener/OpenCLI/blob/49907e53dc3ade5c223ff0c4c2c2785687cec4e6/clis/dribbble/utils.js#L45-L81","documentation":"The URL host is valid dribbble.com, but the pathname does not match /shots/<numeric id>. requireShotTarget requires the path to start with /shots/ followed by digits (optionally followed by '-', '/', or end of path). This ArgumentError is thrown for dribbble.com pages that are not individual shot pages.","triggerScenarios":"Passing URLs like 'https://dribbble.com/halolab' (profile page), 'https://dribbble.com/shots' (listing), 'https://dribbble.com/shots/abc' (non-numeric id), or a shot URL with extra segments the regex doesn't accept.","commonSituations":"Grabbing a designer profile URL when a shot was intended, copying a shots listing page, or saving a URL with a slug-less/typo'd id from bookmarks.","solutions":["Use a URL of the form https://dribbble.com/shots/<numeric id> (trailing slug like /shots/12345-Name is accepted).","If you only have a profile or listing URL, first extract the specific shot id you need and pass that.","Verify the id portion is numeric — alphabetic path segments fail the match."],"exampleFix":"// before\ncli.shot({ shot: 'https://dribbble.com/halolab' }) // profile, not a shot\n\n// after\ncli.shot({ shot: 'https://dribbble.com/shots/1234567-halolab-shot' });","handlingStrategy":"validation","validationCode":"const url = new URL(shot);\nconst m = url.pathname.match(/^\\/shots\\/(\\d+)(?:-|\\/|$)/);\nif (!m) throw new Error('shot URL must be dribbble.com/shots/<numeric id>');","typeGuard":"function isShotPageUrl(v) {\n  try { return /^\\/shots\\/(\\d+)(?:-|\\/|$)/.test(new URL(String(v)).pathname); } catch { return false; }\n}","tryCatchPattern":"try {\n  const result = command({ shot });\n} catch (e) {\n  if (e instanceof ArgumentError && /shots\\/<id>/.test(e.message)) {\n    console.error(`'${shot}' is a dribbble.com page but not a shot page; use /shots/<numeric id>`);\n    return;\n  }\n  throw e;\n}","preventionTips":["Confirm the URL path starts with /shots/ followed by digits before calling.","Don't confuse designer profile URLs (/ha-lolab style) with shot URLs.","Extract the id with your own regex and pass the numeric id to avoid path-shape issues."],"tags":["argument-validation","url-path","format-validation"],"backgroundTag":"invalid-url-format","analyzedSha":"49907e53dc3ade5c223ff0c4c2c2785687cec4e6","analyzedAt":"2026-08-29T08:14:47.543Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}