Stirling-Tools/Stirling-PDF · error · Error

Missing final file data for sharing.

Error message

Missing final file data for sharing.

What it means

Thrown by uploadHistoryChain when the history chain's leaf stub exists in metadata but getStirlingFile(leaf.id) returns null — the latest version's bytes are unreadable/missing.

Source

Thrown at frontend/editor/src/core/services/serverStorageUpload.ts:37

}

export async function uploadHistoryChain(
  originalFileId: FileId,
  existingRemoteId?: number,
): Promise<{ remoteId: number; updatedAt: number; chain: StirlingFileStub[] }> {
  const chain = await fileStorage.getHistoryChainStubs(originalFileId);
  if (chain.length === 0) {
    throw new Error("No history chain found.");
  }

  const finalStub =
    chain
      .slice()
      .reverse()
      .find((stub) => stub.isLeaf !== false) || chain[chain.length - 1];
  const finalFile = await fileStorage.getStirlingFile(finalStub.id);
  if (!finalFile) {
    throw new Error("Missing final file data for sharing.");
  }

  const { bundleFile, manifest } = await buildHistoryBundle(originalFileId);
  const auditLog = new File(
    [JSON.stringify(manifest, null, 2)],
    "audit-log.json",
    {
      type: "application/json",
      lastModified: Date.now(),
    },
  );
  const formData = new FormData();
  formData.append("file", finalFile, finalFile.name);
  formData.append("historyBundle", bundleFile, bundleFile.name);
  formData.append("auditLog", auditLog, auditLog.name);

  if (existingRemoteId) {
    const response = await apiClient.put(

View on GitHub (pinned to 9ef20dcab8)

Solutions

  1. Re-open the latest version in the workbench to re-store its bytes.
  2. Check the leaf stub's dataUnavailable flag before uploading.
  3. Fall back to the most recent readable version in the chain if the leaf is unreadable.

Example fix

// before
const finalFile = await fileStorage.getStirlingFile(finalStub.id);
if (!finalFile) throw new Error('Missing final file data for sharing.');

// after
let finalFile = await fileStorage.getStirlingFile(finalStub.id);
if (!finalFile) {
  // walk backwards to the most recent readable version
  for (const s of chain.slice().reverse()) {
    finalFile = await fileStorage.getStirlingFile(s.id);
    if (finalFile) break;
  }
}
if (!finalFile) throw new Error('No readable version in chain.');
Defensive patterns

Strategy: validation

Validate before calling

const leaf = await fileStorage.getStirlingFileStub(finalStub.id);
if (!leaf || leaf.dataUnavailable) {
  // pick an earlier readable version or abort
}

Type guard

async function readableLeaf(chain: StirlingFileStub[]): Promise<StirlingFileStub | null> {
  for (const s of chain.slice().reverse()) {
    const meta = await fileStorage.getStirlingFileStub(s.id);
    if (meta && !meta.dataUnavailable) return s;
  }
  return null;
}

Prevention

When it happens

Trigger: The leaf stub resolves (isLeaf !== false) but its IndexedDB blob is gone or session-flagged unreadable, while earlier versions or stub metadata remain.

Common situations: WebKit blob eviction hitting only the newest version; partial write during a tool operation; an unreadable record flagged earlier in the session.

Related errors


AI-assisted analysis of Stirling-Tools/Stirling-PDF@9ef20dcab8 (2026-08-13). Data as JSON: /api/errors/bf46ef91da57d5e1. Report an issue: GitHub.