github icereed/paperless-gpt v0.26.0
v0.26.0 - "The Resilience Expansion"

7 hours ago

🚀 paperless-gpt v0.26.0 - "The Resilience Expansion"

The container goes rootless, failed updates stop looping forever, monetary fields finally validate, and Ollama gets thinking-mode and reverse-proxy controls — powered by a huge wave of community contributions!

🌟 Major New Features

🔐 Rootless Container

The Docker container no longer runs as root! On startup it creates a dedicated paperless-gpt user (default 10001:10001), fixes ownership of /app, and drops privileges before launching. Customize with the PUID/PGID environment variables.

  • ⚠️ Upgrade note: if you mount volumes (e.g. prompts/, db/, local hOCR/PDF paths), their ownership will be changed to PUID:PGID on startup. If you need the old behavior, set PUID/PGID to match your host user.
    Thanks to @hensing for this security win — and for bundling, rebasing and pre-verifying 16 community PRs in #990 to make this whole release possible! 🙏

🛡️ Graceful Recovery from Rejected Updates

When paperless-ngx rejects an LLM suggestion (e.g. an impossible date like 2023-01-79), paperless-gpt no longer retries the same document forever — which could rack up real LLM costs. Instead it now:

  • Strips the rejected fields and retries so the valid suggestions still land
  • Removes the auto tag to break the processing loop
  • Applies a new FAIL_TAG (default: paperless-gpt-failed, auto-created) so you can find and review affected documents
    Thanks to @thu1971dlr for tackling this long-standing pain point!

💰 Monetary Custom Field Normalization

LLM-suggested monetary values like USD1,053.52 or EU-style 1.053,52 are now normalized to the canonical format paperless-ngx expects before the update is sent — no more 400 errors and stuck documents from formatting quirks.
Thanks to @bartigas!

🏷️ Let the LLM Create New Tags

With CREATE_NEW_TAGS: "true", the LLM may suggest tags that don't exist in paperless-ngx yet — they'll be created automatically. Off by default, so existing setups are unaffected.
Contributed by @Copilot in #936.

🦙 More Ollama Control

  • OLLAMA_THINK: Disable (or force) Ollama's reasoning mode. Essential for thinking-mode models (Qwen 3, Gemma 3 families) on tasks that need strict output formats — with thinking left on, they can burn the whole token budget reasoning and return empty content. Thanks @dertbv!
  • OLLAMA_HEADERS: Pass arbitrary HTTP headers (e.g. Authorization=Bearer mytoken) to every Ollama request — perfect for Ollama behind an authenticated reverse proxy. Thanks @zebrapurring!

✂️ Content Sanitization Before LLM Calls

Strip scanner watermarks, boilerplate, or sensitive markers from document content before it's sent to the LLM:

  • REMOVE_FROM_CONTENT: comma-separated literal strings
  • REMOVE_FROM_CONTENT_REGEX: semicolon-separated regex patterns
    Thanks to @BieggerM!

📄 Smarter OCR Prompts

The OCR prompt is now rendered per document and can include the text paperless-ngx already extracted ({{.Content}}, capped at 8,000 chars) — giving vision models a reference to cross-check difficult words and numbers against.
Thanks to @adamflagg!

Auto-Processing Completion Tag

Documents finished by the auto pipeline now get an AUTO_TAG_COMPLETE tag (default: paperless-gpt-auto-complete), making it easy to build follow-up workflows. Set it to an empty string to disable.
Thanks to @cfilipov!

🔽 Select-Type Custom Fields

Custom fields of type select now work correctly: LLM-suggested labels are mapped to the option IDs paperless-ngx expects, with proper XML escaping in the prompt.
Thanks to @SEWADE!

🐛 Bug Fixes & Reliability

  • whole_pdf mode fixed: a variable-shadowing bug made totalPdfPages always 0, preventing PDF generation in whole_pdf mode — thanks @chasebolt! (#909)
  • PDF_REPLACE loop fix: tag updates are now skipped for documents that were just replaced, avoiding errors on deleted originals — thanks @chasebolt! (#911)
  • No more crashes on malformed PDFs: gofpdi panics during OCR PDF assembly are recovered so one bad document can't take down the worker — thanks @SAY-5! (#959)
  • Correspondents no longer show as "private": the owner field is omitted when creating correspondents so paperless-ngx assigns the request user — thanks @sobrino89! (#955)
  • Dangling <think> tags cleaned up: OCR reasoning cleanup now handles unclosed think tags — thanks @MilanSchilling! (#915)
  • Data race fixed: settings.CustomFieldsEnable is now read under lock — thanks @adamflagg! (#928)
  • Lighter polling: document polling is throttled (5s interval) when the queue is empty — thanks @Ruben-E! (#987)
  • Version in the footer: the WebUI now shows which version you're running — thanks @Copilot! (#905)
  • Fresh image builds fixed: bumped the pinned musl-dev package after Alpine GC'd the old version, and made the Docker publish workflow fork-aware — thanks @hensing! (#990)
  • E2E stability: the Mistral OCR E2E assertion is now robust against OCR model drift (#991)
  • Docs: docker-compose volume fix by @ce603 (#929) and resource-reservation guidance by @kaindlnetwork (#207)

⚙️ Configuration Highlights

New Environment Variables

# Rootless container
PUID: "10001"                       # User ID to run as (default 10001)
PGID: "10001"                       # Group ID to run as (default 10001)

# Update failure handling
FAIL_TAG: "paperless-gpt-failed"    # Applied when a suggestion is rejected (auto-created)

# Auto-processing
AUTO_TAG_COMPLETE: "paperless-gpt-auto-complete"  # Added when auto-processing finishes ("" to disable)
CREATE_NEW_TAGS: "false"            # Allow the LLM to create brand-new tags

# Ollama
OLLAMA_THINK: "false"               # Disable reasoning mode for thinking-mode models
OLLAMA_HEADERS: "Authorization=Bearer mytoken"  # Headers for reverse-proxy auth

# Content sanitization
REMOVE_FROM_CONTENT: "CONFIDENTIAL,Scanned by XYZ"
REMOVE_FROM_CONTENT_REGEX: "Page \\d+ of \\d+;^Fax:.*$"

⚠️ Behavior Change: Rootless by Default

The container now drops root privileges on startup and chowns /app and mounted app directories to PUID:PGID (default 10001:10001). Most setups need no changes; if your volumes require specific ownership, set PUID/PGID accordingly. All other features are opt-in.


📋 What's Changed

  • Add version display to WebUI footer by @Copilot in #905
  • Skip tag update for replaced document when PDF_REPLACE=true by @chasebolt in #911
  • Fix whole_pdf mode page count mismatch preventing PDF generation by @chasebolt in #909
  • feat: add CREATE_NEW_TAGS env var by @Copilot in #936
  • Bundle of 16 small, pre-verified community PRs by @hensing in #990, including:
  • fix(e2e): make Mistral OCR phrase assertion robust to model drift by @icereed in #991

🎉 New Contributors

A huge welcome to our new contributors — this release is overwhelmingly community-built! 🙌

And a special shout-out to @hensing for assembling, rebasing, conflict-resolving and end-to-end testing the 16-PR community bundle. 💪


Full Changelog: v0.25.1...v0.26.0


Ready to upgrade?

docker pull icereed/paperless-gpt:latest

📚 Check out the README for full documentation on all features!

Don't miss a new paperless-gpt release

NewReleases is sending notifications on new releases.