Stirling-Tools/Stirling-PDF · warning · Error

No history chain found for file.

Error message

No history chain found for file.

What it means

`buildHistoryBundle` calls `fileStorage.getHistoryChainStubs(rootId)`, which returns all stubs whose `originalFileId` (or `id`) equals `rootId`. An empty result throws. So this fires when no stored file traces its lineage back to the supplied root ID — the file isn't in IndexedDB, or it was never versioned into a chain.

Source

Thrown at frontend/editor/src/core/services/serverStorageBundle.ts:53

export async function buildHistoryBundle(
  originalFileIds: FileId[] | FileId,
): Promise<{
  bundleFile: File;
  manifest: ShareBundleManifest;
}> {
  const roots = Array.isArray(originalFileIds)
    ? originalFileIds
    : [originalFileIds];
  const uniqueRoots = Array.from(new Set(roots));
  const allStubs: Array<{
    rootId: FileId;
    stubs: Awaited<ReturnType<typeof fileStorage.getHistoryChainStubs>>;
  }> = [];

  for (const rootId of uniqueRoots) {
    const stubs = await fileStorage.getHistoryChainStubs(rootId);
    if (stubs.length === 0) {
      throw new Error("No history chain found for file.");
    }
    allStubs.push({ rootId, stubs });
  }

  const zip = new JSZip();
  const entries: ShareBundleEntry[] = [];

  for (const chain of allStubs) {
    for (const stub of chain.stubs) {
      const file = await fileStorage.getStirlingFile(stub.id);
      if (!file) {
        throw new Error(`Missing file data for ${stub.name || stub.id}`);
      }

      const logicalId = stub.id;
      const filePath = `files/${logicalId}/${sanitizeFilename(stub.name || "file")}`;
      const buffer = await file.arrayBuffer();
      zip.file(filePath, buffer);

View on GitHub (pinned to 9ef20dcab8)

Solutions

  1. Before sharing, verify the root exists: `const stub = await fileStorage.getStirlingFileStub(rootId); if (!stub) return notify('File not found')`.
  2. If a file genuinely has no chain, offer to share the single current file via `buildSharePackage` instead of `buildHistoryBundle`.
  3. Validate that `rootId` is the original/root ID, not a derived leaf ID.
  4. Handle the case gracefully rather than throwing — return null and let the UI explain.

Example fix

// before
const stubs = await fileStorage.getHistoryChainStubs(rootId);
if (stubs.length === 0) {
  throw new Error("No history chain found for file.");
}

// after
const stubs = await fileStorage.getHistoryChainStubs(rootId);
if (stubs.length === 0) {
  const single = await fileStorage.getStirlingFileStub(rootId);
  if (!single) throw new Error(`File ${rootId} not found in storage`);
  return buildSharePackage([single]);
}
Defensive patterns

Strategy: validation

Validate before calling

// Verify the root exists before building a history bundle
const rootStub = await fileStorage.getStirlingFileStub(rootId);
if (!rootStub) {
  notifyUser("This file is no longer available in local storage.");
  return;
}

Type guard

function isKnownRoot(stub: StirlingFileStub | null): stub is StirlingFileStub {
  return stub !== null;
}

Try / catch

try {
  await buildHistoryBundle(rootId);
} catch (e) {
  if (e instanceof Error && e.message === "No history chain found for file.") {
    notifyUser("No edit history for this file; sharing the current version instead.");
    const single = await fileStorage.getStirlingFileStub(rootId);
    if (single) await buildSharePackage([single]);
  } else throw e;
}

Prevention

When it happens

Trigger: Sharing a `rootId` that was evicted by the LRU cache, cleared by the user, or never persisted (e.g. file still only in memory); passing the wrong ID type (string vs the internal FileId); the file was created in a prior session whose IndexedDB was wiped; calling `buildHistoryBundle` on a freshly-imported file before any tool operation created a history entry.

Common situations: User clears browsing data; Safari/WebKit evicted the blob; ID mismatch after a storage migration; sharing before any edit (no chain exists).

Related errors


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