Skip to content

BuildNot yet confirmed elsewhere1 publisher2 min readPublished

Stirling-PDF does not crash. Your 1 GB container limit becomes a 256 MB heap

A catalogue of 15 self-hosting anti-patterns puts nearly every failure outside the application: default heap sizing, the wrong image variant, a 60-second proxy, OCR with no language pack.

The Engineer · Build desk

How we use AISend a correction

What happened

  • A dev.to catalogue of 15 anti-patterns argues Stirling-PDF itself is stable, and that nearly every crash, hang or mangled output comes from configuration around it.
  • Docker sets no memory limit by default, and the JVM inside the container takes 25 percent of visible RAM as its heap when no -Xmx is given.
  • Three unrelated failures arrive as the same bug report, and the container exit code distinguishes only two of them.
  • A request that never returns, then a 504 at roughly 60 seconds, is the reverse proxy giving up while the job is still running.
  • A fourth mode returns HTTP 200 with vanished text or substituted fonts, and the log records it as a success.

Why it matters

  • constraint Every ceiling that keeps the app from killing its host also guarantees some legitimate large job never finishes, so the limit is a policy about which jobs you refuse, not a safety setting.
  • exposure Anything calling the API unattended is the party most likely to take the host down, since the app queues nothing and holds each accepted request in memory until it finishes.
  • decision On a box already carrying twenty containers, the memory limit and temp volume stop being tuning and become the price of keeping the other services alive.
  • cost The operator pays for misdiagnosis in time, roughly a weekend, because the memory, timeout and settings faults need opposite fixes.

Two ceilings sit inside each other, and only one of them appears in your compose file. The recommendation for a merge-and-split homelab box is the ultra-lite image behind a hard 1 GB container limit [16]. A container-aware JVM with no `-Xmx` set claims a quarter of the RAM it can see [3], which leaves a 256 MB heap [14] inside the gigabyte you thought you were buying. That produces the failure the dev.to write-up says operators skip past, because from outside nothing looks broken: a `java.lang.OutOfMemoryError` stack trace in the log, the web UI still answering, and exactly one job dead [6].

The two-command triage is worth running before touching any configuration, because the exit code separates the host kill from the in-process heap error [9], and either `OOMKilled: true` or a `dmesg` line confirms the first [10]. Neither command says anything about the other two cases, which is the reason three unrelated problems keep arriving under one bug report.

OCR is where the batching advice turns into arithmetic. The scan-hoarder profile in the source is 40,000 pages, the full image, a real tessdata volume with the languages mounted, and batches of 50 pages or fewer [17]. That is 800 submissions [15]. Since cost tracks page count and DPI rather than file count [17], consolidating the scans into fewer PDFs beforehand buys nothing at all.

Office conversion punishes the purchase most operators reach for first. Conversions serialise through a single background LibreOffice process, so effective concurrency is one no matter how many cores you add, and the ordering the source gives is proxy timeout first, CPU later [19]. Every job also writes scratch files to disk before it returns a single byte [4], which is how a working instance fills a volume nobody sized [c5b].

Then there is the variant trap, which costs nothing in memory and still breaks the job: choose a lighter image, then call a tool that image does not contain [12]. Nothing in the heap, the proxy or the cgroup explains that one, and no ceiling you set protects you from it.

What to watch

  • Whether upstream images ship an explicit heap ceiling, which would take the invisible second limit out of operators' hands.
  • Measured pages-per-minute OCR figures at a fixed DPI, which would turn the 50-page batch rule into a budget rather than a habit.
  • Whether a tool missing from a lighter image variant fails loudly enough in the logs to be told apart from a genuine job failure.

Clarity's read

What the record supports and how the coverage leans. The claims behind it follow.

Reality

Evidence38
Adoption
Insufficient
Hype gap+12
Incentives32
Confidence42
Why these scores

Claim ledger

Ranked by verification strength, evidence, and original report placement.

  1. [1]

    Stirling-PDF is described as a stable application: almost every crash, hang and quietly mangled output traces to one of fifteen decisions made outside the app, such as an unbounded container, the wrong image variant, a reverse proxy that gives up after 60 seconds, or an OCR call with no language pack behind it.

    ReportedSupportedSource: dev.to, 15 anti-patterns write-upView cited source
  2. [2]

    Docker applies no memory limit to a container by default.

    ReportedSupportedView cited source
  3. [3]

    A container-aware JVM with no -Xmx set claims a maximum heap of 25 percent of visible RAM.

    ReportedSupportedView cited source

Sources

1 independent publisher whose own reporting we read for this story.

  1. dev.to

    1 article · August 25, 2026

    Why Your Self-Hosted Stirling-PDF Container OOMs, Hangs or Returns a Broken PDF: 15 Anti-Patterns and Their Fixes

Share your take

Let Clarity write the post for you.

Signed-in readers get a short post drafted on this story in the register they choose — narrative, analytical, or a direct position — editable to the last word before it goes anywhere. The share buttons at the top of this story work without an account.

Topics and entities

Follow any of these and your For You feed starts watching them — no settings page required.

Topics

  • Reverse Proxy TimeoutsFollow
  • JVM Container TuningFollow
  • OCR and Document ProcessingFollow
  • Self-Hosted Platform OperationsFollow
  • Container Memory LimitsFollow
  • Failure Triage RunbooksFollow

Entities

Loading related stories