Stirling-Tools/Stirling-PDF · error · Error

No history chain found.

Error message

No history chain found.

What it means

Thrown by uploadHistoryChain when getHistoryChainStubs returns an empty array: no stored stub has originalFileId (or id) equal to the supplied originalFileId. The file has no recorded version history in IndexedDB.

Source

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

function resolveUpdatedAt(value: unknown): number {
  if (!value) {
    return Date.now();
  }
  if (typeof value === "number") {
    return Number.isFinite(value) ? value : Date.now();
  }
  const parsed = new Date(String(value)).getTime();
  return Number.isFinite(parsed) ? parsed : Date.now();
}

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",

View on GitHub (pinned to 9ef20dcab8)

Solutions

  1. Persist the file with fileStorage.storeStirlingFile before calling uploadHistoryChain.
  2. Verify the chain is non-empty via getHistoryChainStubs(originalFileId) before uploading.
  3. For standalone leaves with no history, route to a share path that does not require a chain.

Example fix

// before
const chain = await fileStorage.getHistoryChainStubs(originalFileId);
if (chain.length === 0) throw new Error('No history chain found.');

// after
const chain = await fileStorage.getHistoryChainStubs(originalFileId);
if (chain.length === 0) {
  // ensure the file is stored and self-linked as its own root
  const stored = await fileStorage.getStirlingFileStub(originalFileId);
  if (!stored) throw new Error('File was never stored; import it first.');
  // fall back to a no-history upload path
  return uploadSingleFile(originalFileId, existingRemoteId);
}
Defensive patterns

Strategy: validation

Validate before calling

const chain = await fileStorage.getHistoryChainStubs(originalFileId);
if (chain.length === 0) {
  throw new Error(`No history for ${originalFileId}; store the file first.`);
}

Type guard

async function hasHistoryChain(id: FileId): Promise<boolean> {
  return (await fileStorage.getHistoryChainStubs(id)).length > 0;
}

Prevention

When it happens

Trigger: uploadHistoryChain is called with an originalFileId that was never persisted via storeStirlingFile, whose originalFileId linkage is unset, or whose records were cleared.

Common situations: Passing a raw File/FileId straight to upload without storing it first; user cleared site data; a freshly-imported leaf whose originalFileId was not set to itself; storage eviction removed all versions.

Related errors


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