alyssaxuu/screenity · error · Error

resume-offset-unverified

resume-offset-unverified

Error message

Could not verify server offset during resume.

What it means

When initialize() resumes from a persisted journal with a saved uploadUrl, it queries the TUS server for the current byte offset via getServerOffset() to avoid re-uploading or corrupting data. If the response is not a finite non-negative number, the uploader cannot trust the resume position, marks the uploader error as 'resume-offset-unverified', and throws rather than guessing an offset. This is a safety guard: resuming at a wrong offset would produce a corrupted Bunny video.

Source

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

        }
        throw refreshErr;
      }

      if (this.uploadUrl) {
        const serverOffset = await this.getServerOffset();
        if (Number.isFinite(serverOffset) && serverOffset >= 0) {
          this.lastServerOffset = serverOffset;
          this.offset = serverOffset;
          this.totalBytes = Math.max(this.totalBytes || 0, serverOffset);
          if (this.initializedFromResume || serverOffset > 0) {
            this.emitTelemetry("upload_resumed", {
              resumedOffset: serverOffset,
              resumeCount: this.resumeCount || 1,
            });
          }
        } else {
          this.setUploaderError("resume-offset-unverified");
          throw new Error("Could not verify server offset during resume.");
        }
      } else {
        await this.initTusUpload();
      }

      await this.persistUploadJournal({ force: true });
      this.startHeartbeat();
      this.status = "ready";
      this.readyAt = Date.now();
      this.emitTelemetry("upload_started", {
        resumed: this.initializedFromResume,
        resumeCount: this.resumeCount || 0,
      });
      this.scheduleJournalPersist({ force: true });
      return { videoId: this.videoId, mediaId: this.mediaId };
    } catch (err) {
      if (this.status !== "error") {
        this.setUploaderError("initialize-failed", err);

View on GitHub (pinned to 512606387b)

Solutions

  1. Clear the stale upload journal (uploader.clearUploadJournal()) and call initialize() again so it starts a fresh TUS upload instead of resuming.
  2. Check whether the TUS upload URL still exists (HEAD it manually); a 404 means the video was deleted and resume is impossible — create a new video.
  3. Inspect getServerOffset() response handling: verify the request succeeded and the Upload-Offset header is present; fix parsing if the server changed headers.
  4. If it was a transient network failure during the HEAD, simply retry initialize() — the journal is still intact.
  5. If this recurs, check tus-auth signature expiry: an expired signature can make the offset request fail; ensure refreshTusAuth() succeeds before offset verification.

Example fix

// before
await uploader.initialize({ projectId, sceneId, type });
// after
try {
  await uploader.initialize({ projectId, sceneId, type });
} catch (err) {
  if (err?.message?.includes("verify server offset")) {
    await uploader.clearUploadJournal(); // discard untrusted resume state
    await uploader.initialize({ projectId, sceneId, type }); // fresh upload
  } else throw err;
}
Defensive patterns

Strategy: try-catch

Validate before calling

const res = await fetch(uploadUrl, { method: 'HEAD' });
const offset = Number(res.headers.get('Upload-Offset'));
if (res.ok && Number.isFinite(offset) && offset >= 0) {
  await uploader.initialize({ projectId, sceneId, type }); // safe to resume
}

Type guard

function isVerifiableOffset(v) {
  return typeof v === 'number' && Number.isFinite(v) && v >= 0;
}

Try / catch

try {
  await uploader.initialize({ projectId, sceneId, type });
} catch (err) {
  if (err?.message?.includes('verify server offset') || err?.code === 'resume-offset-unverified') {
    await uploader.clearUploadJournal(); // drop untrusted resume state
    await uploader.initialize({ projectId, sceneId, type }); // fresh upload
  } else throw err;
}

Prevention

When it happens

Trigger: initialize() loaded a resume journal that had an uploadUrl, then getServerOffset() returned NaN/null/undefined or a negative value — e.g. the TUS HEAD request failed, returned an unexpected status, or the Upload-Offset header was missing/unparseable.

Common situations: The Bunny video was deleted server-side (orphan reaper / manual cleanup) so the TUS URL 404s; upload URL expired or signature invalidated between sessions; network error during the offset HEAD request; server response shape changed so the offset header isn't parsed.

Related errors


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