{"record":{"id":"d944f1388d914af4","repo":"jackwener/OpenCLI","slug":"raw-is-a-pinterest-username-url-not-a-b","errorCode":null,"errorMessage":"\"${raw}\" is a Pinterest /${username}/ URL, not a board","messagePattern":"\"(.+?)\" is a Pinterest /(.+?)/ URL, not a board","errorType":"validation","errorClass":"ArgumentError","httpStatus":null,"severity":"error","filePath":"clis/pinterest/utils.js","lineNumber":82,"sourceCode":" * Returns null for anything else (e.g. a bare board id, which needs an API lookup).\n */\nexport function tryParseBoardRef(raw) {\n  const trimmed = String(raw ?? '').trim();\n  if (!trimmed) return null;\n  let pathname = trimmed;\n  if (/^https?:\\/\\//i.test(trimmed)) {\n    try {\n      pathname = new URL(trimmed).pathname;\n    } catch {\n      throw new ArgumentError(`Invalid board URL: ${trimmed}`, 'Use a full board URL like https://www.pinterest.com/janedoe/my-board/');\n    }\n  }\n  // Pinterest percent-encodes non-ASCII slugs in the URLs it hands out; the API wants them decoded.\n  const parts = pathname.split('/').filter(Boolean).map(decodeSegment);\n  if (parts.length < 2) return null;\n  const [username, slug] = parts;\n  if (RESERVED_PATH_ROOTS.has(username.toLowerCase())) {\n    throw new ArgumentError(\n      `\"${raw}\" is a Pinterest /${username}/ URL, not a board`,\n      username.toLowerCase() === 'pin'\n        ? 'Pass the board this pin lives on, e.g. janedoe/my-board (`opencli pinterest pin <id>` reports it)'\n        : 'Pass <username>/<slug>, a board URL, or a numeric board id',\n    );\n  }\n  return { username, slug, path: `/${username}/${slug}/` };\n}\n\n/** Normalize a username or profile URL to a bare username (Pinterest has no @-handles). */\nexport function parseUsername(raw) {\n  let value = String(raw ?? '').trim();\n  if (!value) throw new ArgumentError('username is required', 'Pass a Pinterest username or profile URL, e.g. janedoe');\n  if (/^https?:\\/\\//i.test(value)) {\n    try {\n      value = decodeSegment(new URL(value).pathname.split('/').filter(Boolean)[0] || '');\n    } catch {\n      throw new ArgumentError(`Invalid profile URL: ${raw}`, 'Use a full profile URL like https://www.pinterest.com/janedoe/');","sourceCodeStart":64,"sourceCodeEnd":100,"githubUrl":"https://github.com/jackwener/OpenCLI/blob/49907e53dc3ade5c223ff0c4c2c2785687cec4e6/clis/pinterest/utils.js#L64-L100","documentation":"tryParseBoardRef rejects Pinterest URLs whose first path segment is a reserved root such as /pin/ rather than a username. Those URLs point at pins or other Pinterest resources, not boards, so throwing prevents silently misinterpreting the reference. The hint for /pin/ URLs points users at `opencli pinterest pin <id>` to discover the owning board.","triggerScenarios":"Passing https://www.pinterest.com/pin/1234567890123456/ (or another reserved root like /search/, /today/) to a board-parsing command; the first path segment lowercased is in RESERVED_PATH_ROOTS.","commonSituations":"Copying a pin URL from the browser when you meant the board URL; sharing links from an email that point at pins; automation that always pastes the current page URL.","solutions":["If it's a /pin/ URL, run `opencli pinterest pin <id>` to find the board, then pass that board","Pass the board as username/slug, e.g. janedoe/my-board","Pass the board's canonical URL https://www.pinterest.com/<user>/<slug>/","Pass the numeric board id instead of a resource URL"],"exampleFix":"// before\nawait direct('https://www.pinterest.com/pin/1234567890123456/');\n// after\nawait direct('janedoe/my-board'); // board the pin lives on","handlingStrategy":"validation","validationCode":"const RESERVED = new Set(['pin', 'search', 'today', 'ideas', 'resource']);\nfunction looksLikeBoardUrl(s) {\n  if (!/^https?:\\/\\//i.test(s || '')) return true;\n  const seg = new URL(s).pathname.split('/').filter(Boolean)[0];\n  return seg ? !RESERVED.has(seg.toLowerCase()) : false;\n}","typeGuard":"const isPinUrl = (v) => typeof v === 'string' && /(^|\\/)pin\\/\\d+/.test(v);","tryCatchPattern":"try {\n  ref = tryParseBoardRef(input);\n} catch (err) {\n  if (err instanceof ArgumentError && /not a board/.test(err.message)) {\n    console.error(`${err.message}\\n${err.hint}`); // hint says to use `pinterest pin <id>`\n    process.exitCode = 2;\n  } else throw err;\n}","preventionTips":["Detect /pin/ URLs first and route them to the pin API, not board parsing","Extract the board from a pin lookup (opencli pinterest pin <id>) before board calls","Sanction only canonical board URLs of the form /<user>/<slug>/","When sharing links internally, copy the board URL, not the current page URL"],"tags":["url-parsing","argument-error","wrong-resource-type","pinterest"],"backgroundTag":"wrong-resource-type","analyzedSha":"49907e53dc3ade5c223ff0c4c2c2785687cec4e6","analyzedAt":"2026-08-29T08:14:47.543Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}