{"record":{"id":"45e8c1dffbed5f73","repo":"jackwener/OpenCLI","slug":"invalid-board-url-trimmed","errorCode":null,"errorMessage":"Invalid board URL: ${trimmed}","messagePattern":"Invalid board URL: (.+?)","errorType":"validation","errorClass":"ArgumentError","httpStatus":null,"severity":"error","filePath":"clis/pinterest/utils.js","lineNumber":74,"sourceCode":"    return decodeURIComponent(segment);\n  } catch {\n    return segment;\n  }\n}\n\n/**\n * Parse a board URL or <username>/<slug> into { username, slug, path }.\n * 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). */","sourceCodeStart":56,"sourceCodeEnd":92,"githubUrl":"https://github.com/jackwener/OpenCLI/blob/49907e53dc3ade5c223ff0c4c2c2785687cec4e6/clis/pinterest/utils.js#L56-L92","documentation":"tryParseBoardRef accepts a board URL, a username/slug path, or a numeric id. When the input looks like an http(s) URL but cannot be parsed by the URL constructor, this ArgumentError is thrown. It catches malformed URLs early rather than producing a bogus board reference.","triggerScenarios":"Passing a string starting with http:// or https:// that new URL() rejects — e.g. 'https://pinterest com/janedoe/my-board' (space), 'https://', or a truncated/corrupted URL from a script.","commonSituations":"Shell splitting broke the URL at '&' or '?'; a template variable was empty producing 'https:///...'; smart quotes or invisible characters pasted from docs; an env var holding the board URL was only partially set.","solutions":["Pass a full, well-formed board URL like https://www.pinterest.com/janedoe/my-board/","Quote the URL in your shell so special characters don't break it","Or skip the URL entirely and pass username/slug (janedoe/my-board) or a numeric board id","Check for stray spaces/whitespace — trim the input before calling"],"exampleFix":"// before\nawait direct(process.env.BOARD_URL); // 'https://pinterest.com/janedoe/my board'\n// after\nconst url = (process.env.BOARD_URL || '').trim().replace(/ /g, '-');\nawait direct(url); // or pass 'janedoe/my-board'","handlingStrategy":"validation","validationCode":"function isParseableUrl(s) {\n  if (typeof s !== 'string' || !/^https?:\\/\\//i.test(s.trim())) return true; // not a URL, other paths apply\n  try { new URL(s.trim()); return true; } catch { return false; }\n}\nif (!isParseableUrl(boardRef)) boardRef = boardRef.trim(); // or reject before calling","typeGuard":"const isHttpUrl = (v) => {\n  if (typeof v !== 'string' || !/^https?:\\/\\//i.test(v)) return false;\n  try { new URL(v); return true; } catch { return false; }\n};","tryCatchPattern":"let board;\ntry {\n  board = tryParseBoardRef(input);\n} catch (err) {\n  if (err instanceof ArgumentError && err.message.startsWith('Invalid board URL')) {\n    console.error(`${err.message} — ${err.hint}`);\n    process.exitCode = 2;\n  } else throw err;\n}","preventionTips":["Quote URLs in shell commands so &, ?, and spaces survive","Trim and strip whitespace/smart quotes from pasted URLs","Prefer username/slug or numeric id inputs in scripts over raw URLs","Validate env-var URLs once at startup with new URL() in a try/catch"],"tags":["url-parsing","argument-error","malformed-url","input-validation"],"backgroundTag":"invalid-url-format","analyzedSha":"49907e53dc3ade5c223ff0c4c2c2785687cec4e6","analyzedAt":"2026-08-29T08:14:47.543Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}