{"record":{"id":"6a4284bae068aa2b","repo":"jackwener/OpenCLI","slug":"invalid-profile-url-raw","errorCode":null,"errorMessage":"Invalid profile URL: ${raw}","messagePattern":"Invalid profile URL: (.+?)","errorType":"validation","errorClass":"ArgumentError","httpStatus":null,"severity":"error","filePath":"clis/pinterest/utils.js","lineNumber":100,"sourceCode":"    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/');\n    }\n  }\n  value = value.replace(/^\\/+|\\/+$/g, '');\n  if (!value) throw new ArgumentError(`Not a username: \"${raw}\"`, 'Pass the bare username, e.g. janedoe');\n  if (value.includes('/')) {\n    throw new ArgumentError(\n      `Not a username: \"${raw}\"`,\n      'This looks like a board or pin reference — pass just the username, e.g. janedoe',\n    );\n  }\n  if (value.startsWith('@')) {\n    throw new ArgumentError(`Pinterest usernames have no \"@\": \"${raw}\"`, 'Drop the @ and use the bare username, e.g. janedoe');\n  }\n  return value;\n}\n\n/** Parse a bare pin id or a /pin/<id>/ URL. */\nexport function parsePinId(raw) {","sourceCodeStart":82,"sourceCodeEnd":118,"githubUrl":"https://github.com/jackwener/OpenCLI/blob/49907e53dc3ade5c223ff0c4c2c2785687cec4e6/clis/pinterest/utils.js#L82-L118","documentation":"When parseUsername receives a string that starts with http(s)://, it tries to parse it as a profile URL and extract the first path segment. If the URL constructor throws, this ArgumentError is raised with guidance to use a full profile URL. It distinguishes 'malformed URL' from 'not a username' so the fix message is precise.","triggerScenarios":"Passing an unparseable http(s) string such as 'https://pinterest com/janedoe' (space), 'https://', or a URL mangled by shell quoting to parseUsername.","commonSituations":"URL broken by an unescaped '&' or spaces in a shell command; pasted URL containing smart quotes; template placeholder never substituted ('${PROFILE_URL}'); truncated URL from a log line.","solutions":["Pass a full, well-formed profile URL like https://www.pinterest.com/janedoe/","Or simply pass the bare username janedoe — no URL needed","Quote the URL in your shell so special characters survive","Check for whitespace/smart quotes and clean the string before calling"],"exampleFix":"// before\nconst user = parseUsername('https://pinterest com/janedoe/');\n// after\nconst user = parseUsername('https://www.pinterest.com/janedoe/'); // or just 'janedoe'","handlingStrategy":"validation","validationCode":"function isCleanProfileUrl(s) {\n  if (!/^https?:\\/\\//i.test(s || '')) return true;\n  try { new URL(s.trim()); return true; } catch { return false; }\n}\nif (!isCleanProfileUrl(input)) input = input.trim().replace(/[\\s\\u2018\\u2019]/g, '');","typeGuard":"const isUrl = (v) => { try { new URL(v); return true; } catch { return false; } };","tryCatchPattern":"try {\n  username = parseUsername(input);\n} catch (err) {\n  if (err instanceof ArgumentError && err.message.startsWith('Invalid profile URL')) {\n    console.error(`${err.message} — ${err.hint}`);\n    process.exitCode = 2;\n  } else throw err;\n}","preventionTips":["Store bare usernames in config; URLs are only for humans","encodeURIComponent/decode round-trips only on path segments you control","Check for template placeholders (${...}) left unsubstituted in config","Trim and strip smart quotes from any pasted value"],"tags":["url-parsing","argument-error","malformed-url","username"],"backgroundTag":"invalid-url-format","analyzedSha":"49907e53dc3ade5c223ff0c4c2c2785687cec4e6","analyzedAt":"2026-08-29T08:14:47.543Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}