{"record":{"id":"6edcda0eeb272958","repo":"jackwener/OpenCLI","slug":"shot-url-must-use-dribbble-com","errorCode":null,"errorMessage":"shot URL must use dribbble.com","messagePattern":"shot URL must use dribbble\\.com","errorType":"validation","errorClass":"ArgumentError","httpStatus":null,"severity":"error","filePath":"clis/dribbble/utils.js","lineNumber":60,"sourceCode":"    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}` : '';\n        throw new CommandExecutionError(`${command} selector drift${reason}`);\n    }\n    if (!Array.isArray(payload.rows)) {","sourceCodeStart":42,"sourceCodeEnd":78,"githubUrl":"https://github.com/jackwener/OpenCLI/blob/49907e53dc3ade5c223ff0c4c2c2785687cec4e6/clis/dribbble/utils.js#L42-L78","documentation":"After a shot value parses as a URL, requireShotTarget checks that the hostname is dribbble.com or a subdomain of it. This ArgumentError is thrown when a valid URL points at a different host, because the library only scrapes dribbble.com shot pages.","triggerScenarios":"Passing URLs from other sites (e.g. 'https://www.behance.net/gallery/123', 'https://example.com/shots/123') or mirror/proxied hosts that are not dribbble.com or *.dribbble.com.","commonSituations":"Mixing up shot links from other design sites stored in the same dataset, using a shortened link (bit.ly etc.) that resolves to a non-dribbble host string, or a typo like 'dribbble.org'.","solutions":["Use the canonical https://dribbble.com/shots/<id> URL.","Extract the numeric id from wherever the link came from and pass the id instead of the URL.","Check for typos in the hostname and ensure redirects are resolved to dribbble.com before passing the URL."],"exampleFix":"// before\ncli.shot({ shot: 'https://www.behance.net/gallery/123456/Shot' })\n\n// after\ncli.shot({ shot: 'https://dribbble.com/shots/123456' }); // or just 123456","handlingStrategy":"validation","validationCode":"const url = new URL(shot);\nif (!/(^|\\.)dribbble\\.com$/i.test(url.hostname)) {\n  throw new Error(`shot URL must point at dribbble.com, got ${url.hostname}`);\n}","typeGuard":"function isDribbbleUrl(v) {\n  try { return /(^|\\.)dribbble\\.com$/i.test(new URL(String(v)).hostname); } catch { return false; }\n}","tryCatchPattern":"try {\n  const result = command({ shot });\n} catch (e) {\n  if (e instanceof ArgumentError && /shot URL must use dribbble\\.com/.test(e.message)) {\n    console.error('Only dribbble.com shot URLs are supported; extract the id and pass that instead');\n    return;\n  }\n  throw e;\n}","preventionTips":["Store canonical dribbble.com shot URLs in your data, not links from other sites.","Resolve short links/redirects before passing them if you cannot guarantee the host.","Check hostnames for typos (dribbble.org, dribble.com) in stored data."],"tags":["argument-validation","url-host","domain-validation"],"backgroundTag":"invalid-url-format","analyzedSha":"49907e53dc3ade5c223ff0c4c2c2785687cec4e6","analyzedAt":"2026-08-29T08:14:47.543Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}