alyssaxuu/screenity · error · Error

Failed to start TUS upload session

Error message

Failed to start TUS upload session

What it means

BunnyTusUploader creates a TUS upload session by POSTing to Bunny's video CDN creation endpoint and throws this when the HTTP response is not ok. It means Bunny rejected session creation (auth, quota, container/metadata, or network-level failure surfaced as a non-2xx), so no upload URL exists and no bytes can be sent.

Source

Thrown at src/pages/CloudRecorder/bunnyTusUploader.js:1214

  }

  async initTusUpload() {
    const res = await fetch("https://video.bunnycdn.com/tusupload", {
      method: "POST",
      headers: {
        "Tus-Resumable": "1.0.0",
        "Upload-Defer-Length": "1",
        AuthorizationSignature: this.signature,
        AuthorizationExpire: String(this.expires),
        LibraryId: String(this.libraryId),
        VideoId: this.videoId,
        "Upload-Metadata": `filetype ${btoa(this.container || "video/webm")},title ${btoa(
          this.metadata.title,
        )}`,
      },
    });

    if (!res.ok) throw new Error("Failed to start TUS upload session");
    const location = res.headers.get("location");
    const resolved = location.startsWith("/")
      ? `https://video.bunnycdn.com${location}`
      : location;
    // Defense-in-depth: TUS Location header must stay on Bunny's host. Without
    // this, a redirect to attacker.com would receive subsequent PATCHes
    // carrying recording chunks plus the AuthorizationSignature header.
    try {
      const parsed = new URL(resolved);
      if (parsed.host !== "video.bunnycdn.com") {
        throw new Error(`Untrusted TUS location host: ${parsed.host}`);
      }
    } catch (err) {
      throw new Error(`Invalid TUS location: ${err?.message || err}`);
    }
    this.uploadUrl = resolved;

    // Persist BEFORE save-upload-meta: the local journal is the only recovery

View on GitHub (pinned to 512606387b)

Solutions

  1. Log res.status and res body at the throw site to identify which 4xx/5xx Bunny returned
  2. Refresh the Bunny auth signature/token before creating the session and retry once
  3. Ensure metadata values are ASCII-safe before btoa (use a UTF-8 safe base64 encoder for the title)
  4. Verify the library id and create endpoint URL match your Bunny account/region
  5. Check Bunny status/incidents if failures are widespread

Example fix

// before
if (!res.ok) throw new Error("Failed to start TUS upload session");
// after
if (!res.ok) {
  const body = await res.text().catch(() => "");
  throw new Error(`Failed to start TUS upload session: HTTP ${res.status} ${body.slice(0, 200)}`);
}
Defensive patterns

Strategy: try-catch

Validate before calling

// before creating a session
if (!bunnyToken) throw new Error("missing Bunny auth token");
const res = await fetch(createUrl, { method: "POST", headers });
if (!res.ok) console.error("TUS create failed", res.status, await res.text());

Try / catch

try {
  await uploader.init();
} catch (e) {
  if (String(e.message).includes("Failed to start TUS upload session")) {
    await refreshBunnyToken();
    await uploader.init(); // single retry after re-auth
  } else throw e;
}

Prevention

When it happens

Trigger: POST to the TUS creation endpoint returns non-ok status: invalid or expired AuthorizationSignature/token, missing or mis-encoded Upload-Metadata (e.g. non-ASCII title that btoa cannot encode), wrong collection/container id, or Bunny outage returning 4xx/5xx.

Common situations: Expired Bunny API key or signed upload token; recording started after auth expired; btoa throwing on Unicode metadata upstream; wrong library id in the creation URL; CORS/proxy stripping the Location header in dev environments.

Related errors


AI-assisted analysis of alyssaxuu/screenity@512606387b (2026-09-02). Data as JSON: /api/errors/955afb4605a001eb. Report an issue: GitHub.