Repository navigation
Description
Summary
Could Presidio provide a configurable input-size safeguard for the default spaCy-backed analyzer, or document a supported bounded-processing configuration for memory-constrained deployments?
This is a request about predictable resource usage, not a claim that all inputs over 100,000 characters fail.
Problem and evidence
Our deployment notes record Presidio analyzer 2.2.362 pods being OOMKilled (exit 137) under a 2Gi memory limit after repeated requests. We do not have a complete reproduction trace, exact payload lengths, or peak-memory measurements to attach. A subsequent configuration reduces Gunicorn concurrency to one worker; we have not demonstrated that this makes large or repeated requests safe.
Source inspection of the latest release, 2.2.366, shows:
- The stock Dockerfile still selects
conf/default.yaml, which configuresspacywithen_core_web_lg. SpacyNlpEngineis unchanged from 2.2.362:process_text()invokes the entire pipeline on the supplied text, andprocess_batch()processes each entire document throughnlp.pipe()./analyzehas no explicit application-level text-length/body-size safeguard or automatic per-document splitting before NLP processing.- Selecting only
CREDIT_CARD,US_SSN,IBAN_CODE,EMAIL_ADDRESS, andPHONE_NUMBERdoes not bypass the default NLP preprocessing.
spaCy's default max_length of 1,000,000 characters is not a memory-budget guarantee. Its E088 message warns that parser/NER processing can require roughly 1GB of temporary memory per 100,000 characters; this is guidance, not a universal failure threshold.
Suggested investigation
We have not executed this sample against 2.2.366. It is a candidate workload for an isolated, memory-limited test environment, not a verified reproducer. Do not run it against a shared or production analyzer.
from presidio_analyzer import AnalyzerEngine
analyzer = AnalyzerEngine()
entities = ["CREDIT_CARD", "US_SSN", "IBAN_CODE", "EMAIL_ADDRESS", "PHONE_NUMBER"]
seed = "Please contact [email protected] about the order status. "
for size in (100_000, 200_000, 500_000):
text = (seed * (size // len(seed) + 1))[:size]
for _ in range(3):
print(f"Analyzing {len(text)} characters", flush=True)
analyzer.analyze(text=text, language="en", entities=entities)For the HTTP path, use a dedicated container with one Gunicorn worker and a 2Gi memory limit, exercise equivalent payloads through /analyze, and record peak RSS/cgroup memory, exit status, and whether memory stabilizes between sequential requests. The sample cannot predict the OOM threshold; tokenization and text shape matter.
Expected behavior / requested improvement
An explicitly configured safety boundary should reject an oversized input before costly NLP processing, with a documented error and no silent truncation or skipped PII inspection. A character cap and an HTTP body cap address different stages and could be documented separately.
If caller-side overlapping chunking remains the recommended solution, please document a supported configuration and its limitations: entity offsets, boundary-spanning entities, throughput, and the fact that a safe chunk size depends on the model and available memory.
Please also clarify the supported configuration for structural-only recognizers using NoOpNlpEngine, including the loss of text-derived context enhancement and resulting score-threshold implications.
Existing work and related issues
We recognize that SlimSpacyNlpEngine and NoOpNlpEngine are available in newer releases. They are optional alternatives, not a change to the stock spaCy path. We are not requesting that Presidio automatically disable NLP based on an entity list.
- Large-text limit / caller-side chunking discussion #957
- Long text chunking #1571
- Memory retention discussion #896; we have not established that our observations are the same issue.
- No-op NLP engine #2071
- Tokenizer-based chunking for HuggingFace/GLiNER recognizers #2041; this does not add a safeguard to default spaCy preprocessing.
Source references: spaCy engine, default NLP configuration, HTTP analyzer, Dockerfile.
Activity
valbarov commentedon Nov 10, 2026
I'd like to work on a first, narrow part of this: an opt-in limit on text length.
Proposal:
AnalyzerEngine(max_text_length=None). The default keeps current behavior.TextTooLongError(aValueError) before the NLP engine runs. No truncation, so nothing is skipped silently.BatchAnalyzerEnginechecks each value before NLP processing. One oversized text fails the call.max_text_lengthas a key in the analyzer YAML, validated at load time./analyzereturns 413 with a clear message instead of the generic 500.Out of scope for this PR: automatic chunking in the spaCy path, an HTTP body-size cap, and the
NoOpNlpEnginedocs. Those can follow separately.Two questions before I open the PR:
AnalyzerEngine, or on the NLP engine config?