Stirling-Tools/Stirling-PDF · error · Error

File ${file.name} appears to be corrupted

Error message

File ${file.name} appears to be corrupted

What it means

`processFile` calls `FileAnalyzer.analyzeFile`, which runs pdf.js (`quickPDFAnalysis`) and flags `isCorrupted=true` whenever pdf.js throws an error that does NOT contain 'password'/'encrypted'. So 'corrupted' really means 'pdf.js could not parse this file for any non-encryption reason' — it is a catch-all, not a true structural-corruption check.

Source

Thrown at frontend/editor/src/core/services/enhancedPDFProcessingService.ts:74

  ): Promise<ProcessedFile | null> {
    const fileKey = await this.generateFileKey(file);

    // Check cache first
    const cached = this.cache.get(fileKey);
    if (cached) {
      this.updateMetrics("cacheHit");
      return cached;
    }

    // Check if already processing
    if (this.processing.has(fileKey)) {
      return null;
    }

    // Analyze file to determine optimal strategy
    const analysis = await FileAnalyzer.analyzeFile(file);
    if (analysis.isCorrupted) {
      throw new Error(`File ${file.name} appears to be corrupted`);
    }

    // Create processing config
    const config: ProcessingConfig = {
      ...this.defaultConfig,
      strategy: analysis.recommendedStrategy,
      ...customConfig,
    };

    // Start processing
    this.startProcessing(
      file,
      fileKey,
      config,
      analysis.estimatedProcessingTime,
    );
    return null;
  }

View on GitHub (pinned to 9ef20dcab8)

Solutions

  1. Before `processFile`, call `FileAnalyzer.isValidPDF(file)` (checks `%PDF-` header) to reject obvious non-PDFs with a clear message.
  2. Distinguish 'worker unavailable' from 'corrupt file': if `pdfWorkerManager` failed to initialise, treat that as a service error, not corruption.
  3. Offer the user a repair/re-upload path and surface the original pdf.js error message (currently swallowed) so the cause is diagnosable.
  4. If the file is large, confirm it isn't merely a slow parse — the analyzer parses synchronously and a timeout looks identical to corruption.

Example fix

// before
const analysis = await FileAnalyzer.analyzeFile(file);
if (analysis.isCorrupted) {
  throw new Error(`File ${file.name} appears to be corrupted`);
}

// after (cheap header check + richer cause)
const analysis = await FileAnalyzer.analyzeFile(file);
if (analysis.isCorrupted) {
  const validHeader = await FileAnalyzer.isValidPDF(file);
  throw new Error(
    validHeader
      ? `File ${file.name} could not be parsed (may be damaged or use an unsupported feature)`
      : `File ${file.name} is not a valid PDF`,
  );
}
Defensive patterns

Strategy: validation

Validate before calling

// Reject obvious non-PDFs before the heavy analyze step
const isValid = await FileAnalyzer.isValidPDF(file);
if (!isValid) {
  notifyUser(`${file.name} is not a valid PDF`);
  return;
}

Type guard

function isLikelyPdf(file: File): boolean {
  return file.type === "application/pdf" || file.name.toLowerCase().endsWith(".pdf");
}

Try / catch

try {
  const result = await service.processFile(file);
} catch (e) {
  const msg = e instanceof Error ? e.message : "";
  if (msg.includes("appears to be corrupted")) {
    notifyUser(`${file.name} could not be parsed. It may be damaged or in an unsupported format.`);
  } else { throw e; }
}

Prevention

When it happens

Trigger: Uploading a non-PDF file renamed to `.pdf`; a truncated or half-downloaded PDF; a PDF with a broken xref/trailer; a file the pdf.js worker failed to fetch into (worker crashed/timed out); zero-byte file. Also fires if the pdf.js worker itself is misconfigured and `createDocument` rejects for unrelated reasons.

Common situations: User renames an image/doc to `.pdf`; download interrupted leaving a partial file; older pdf.js worker version choking on a valid newer-PDF feature (e.g. PDF 2.0); the Web Worker that hosts pdf.js failed to spawn so every file 'fails to parse'.

Related errors


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