schollz/croc · error

Invalid stored-transfer URL

Error message

Invalid stored-transfer URL

What it means

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.

Source

Thrown at web/src/protocol/stored.ts:193

  if (trimmed.startsWith(`${storedProtocol}.`)) {
    const parts = trimmed.split(".");
    if (parts.length !== 4) throw new Error("Invalid stored-transfer token");
    return validateShare({
      origin: textDecoder.decode(fromBase64URL(parts[1])),
      id: parts[2],
      key: fromBase64URL(parts[3]),
    });
  }
  const parsed = new URL(trimmed);
  const match = parsed.pathname.match(/^\/s\/([A-Za-z0-9_-]{22})$/);
  if (
    !match ||
    parsed.username ||
    parsed.password ||
    parsed.search ||
    !parsed.hash.startsWith("#v1.")
  ) {
    throw new Error("Invalid stored-transfer URL");
  }
  return validateShare({
    origin: parsed.origin,
    id: match[1],
    key: fromBase64URL(parsed.hash.slice(4)),
  });
}

export function storedShareFromLocation(location: Location = window.location) {
  if (!/^\/s\/[A-Za-z0-9_-]{22}$/.test(location.pathname)) return undefined;
  if (!location.hash.startsWith("#v1.")) return undefined;
  return parseStoredShare(location.href);
}

export function isStoredShareValue(value: string) {
  const trimmed = value.trim();
  if (trimmed.startsWith(`${storedProtocol}.`)) return true;
  try {

View on GitHub (pinned to e25f1bdc04)

Solutions

  1. Use the pristine link generated by the sender — no trackers, no extra path, and the #v1. key fragment intact
  2. Strip query strings and normalize the path before parsing if you must accept wrapped URLs
  3. Detect share-shaped input first with isStoredShareValue() or storedShareFromLocation() to give a friendly prompt instead of an exception

Example fix

// before
const share = parseStoredShare(input); // throws if input has ?utm_source=...

// after
const cleaned = input.trim().replace(/[?#].*$/, (m) => (m.startsWith("#v1.") ? m : ""));
const share = parseStoredShare(cleaned);
Defensive patterns

Strategy: validation

Validate before calling

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; } };

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Related errors


AI-assisted analysis of schollz/croc@e25f1bdc04 (2026-08-15). Data as JSON: /api/errors/eba95a3a6c82f0f2. Report an issue: GitHub.