{"record":{"id":"eba95a3a6c82f0f2","repo":"schollz/croc","slug":"invalid-stored-transfer-url","errorCode":null,"errorMessage":"Invalid stored-transfer URL","messagePattern":"Invalid stored-transfer URL","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"web/src/protocol/stored.ts","lineNumber":193,"sourceCode":"  if (trimmed.startsWith(`${storedProtocol}.`)) {\n    const parts = trimmed.split(\".\");\n    if (parts.length !== 4) throw new Error(\"Invalid stored-transfer token\");\n    return validateShare({\n      origin: textDecoder.decode(fromBase64URL(parts[1])),\n      id: parts[2],\n      key: fromBase64URL(parts[3]),\n    });\n  }\n  const parsed = new URL(trimmed);\n  const match = parsed.pathname.match(/^\\/s\\/([A-Za-z0-9_-]{22})$/);\n  if (\n    !match ||\n    parsed.username ||\n    parsed.password ||\n    parsed.search ||\n    !parsed.hash.startsWith(\"#v1.\")\n  ) {\n    throw new Error(\"Invalid stored-transfer URL\");\n  }\n  return validateShare({\n    origin: parsed.origin,\n    id: match[1],\n    key: fromBase64URL(parsed.hash.slice(4)),\n  });\n}\n\nexport function storedShareFromLocation(location: Location = window.location) {\n  if (!/^\\/s\\/[A-Za-z0-9_-]{22}$/.test(location.pathname)) return undefined;\n  if (!location.hash.startsWith(\"#v1.\")) return undefined;\n  return parseStoredShare(location.href);\n}\n\nexport function isStoredShareValue(value: string) {\n  const trimmed = value.trim();\n  if (trimmed.startsWith(`${storedProtocol}.`)) return true;\n  try {","sourceCodeStart":175,"sourceCodeEnd":211,"githubUrl":"https://github.com/schollz/croc/blob/e25f1bdc04f07f094d50b0a1bf67e2563944b57a/web/src/protocol/stored.ts#L175-L211","documentation":"The URL branch of parseStoredShare() demands a strict share URL shape: pathname exactly /s/<22 base64url chars>, no username/password, no query string, and a fragment beginning with #v1.. Anything else — wrong path, a ?query appended, missing or wrong-prefixed key fragment — throws.","triggerScenarios":"parseStoredShare(\"https://host/s/ID?utm=...\") — query string present; a URL without the #v1. key fragment; a path like /share/ID or /s/ID/extra; a URL with embedded credentials.","commonSituations":"Share links run through analytics/redirect wrappers that append query parameters; users sharing the URL without the fragment (fragments are often stripped when links are re-shared in some clients); typos in the path.","solutions":["Use the pristine link generated by the sender — no trackers, no extra path, and the #v1. key fragment intact","Strip query strings and normalize the path before parsing if you must accept wrapped URLs","Detect share-shaped input first with isStoredShareValue() or storedShareFromLocation() to give a friendly prompt instead of an exception"],"exampleFix":"// before\nconst share = parseStoredShare(input); // throws if input has ?utm_source=...\n\n// after\nconst cleaned = input.trim().replace(/[?#].*$/, (m) => (m.startsWith(\"#v1.\") ? m : \"\"));\nconst share = parseStoredShare(cleaned);","handlingStrategy":"validation","validationCode":"const looksLikeShareURL = (v: string): boolean => { try { const u = new URL(v.trim()); return /^\\/s\\/[A-Za-z0-9_-]{22}$/.test(u.pathname) && u.hash.startsWith(\"#v1.\") && !u.username && !u.password && !u.search; } catch { return false; } };","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Strip tracking query params and verify the #v1. fragment exists before parsing","Use storedShareFromLocation() on the receive page instead of re-parsing arbitrary strings"],"tags":["validation","url","parsing","share-link"],"backgroundTag":null,"analyzedSha":"e25f1bdc04f07f094d50b0a1bf67e2563944b57a","analyzedAt":"2026-08-15T12:53:39.096Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}