🚀 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 toPUID:PGIDon startup. If you need the old behavior, setPUID/PGIDto 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 stringsREMOVE_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
totalPdfPagesalways 0, preventing PDF generation inwhole_pdfmode — 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:
gofpdipanics 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
ownerfield 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.CustomFieldsEnableis 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-devpackage 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:
- Reduce document polling load by @Ruben-E in #987
OLLAMA_THINKenv var by @dertbv in #983- Normalize monetary custom field values by @bartigas in #978
- Break auto-tag loop on update rejection by @thu1971dlr in #976
- Recover from gofpdi panic on malformed PDFs by @SAY-5 in #959
- Drop
ownerfield from correspondent POST when nil by @sobrino89 in #955 - Resolve select-field label-to-ID mapping for custom fields by @SEWADE in #943
OLLAMA_HEADERSsupport by @zebrapurring in #938- README docker-compose volume fix by @ce603 in #929
- Fix data race on
settings.CustomFieldsEnableby @adamflagg in #928 - Per-document OCR prompt rendering by @adamflagg in #925
- Content sanitization for LLM API calls by @BieggerM in #917
- Fix OCR reasoning cleanup for dangling
<think>tags by @MilanSchilling in #915 AUTO_TAG_COMPLETEenv var by @cfilipov in #892- Docker Compose resource-reservation docs by @kaindlnetwork in #207
- Run Docker container as non-root user by @hensing in #722
- 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! 🙌
- @chasebolt made their first contribution in #911
- @Ruben-E made their first contribution in #987
- @dertbv made their first contribution in #983
- @bartigas made their first contribution in #978
- @thu1971dlr made their first contribution in #976
- @SAY-5 made their first contribution in #959
- @sobrino89 made their first contribution in #955
- @SEWADE made their first contribution in #943
- @zebrapurring made their first contribution in #938
- @ce603 made their first contribution in #929
- @adamflagg made their first contribution in #925
- @BieggerM made their first contribution in #917
- @MilanSchilling made their first contribution in #915
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!