Troubleshooting & Common Errors¶
This page maps the concrete failures you are most likely to hit — symptom → cause → fix. It quotes exact OpenMed-owned error strings and gives the command or configuration change for each case; wrapped operating-system, network, and third-party errors can vary. If your problem is conceptual rather than an error, start with the FAQ; if you are setting up for the first time, see the Quick Start and Configuration & Validation.
Run the built-in doctor first
Before digging in, run the offline environment check. It reports your Python version and architecture, which selected runtime extras are importable, whether an HF_TOKEN is present, and whether offline mode is active. Dependency, token, Python-version, and architecture checks that need action include a remediation Hint:.
openmed doctor # human-readable check list
openmed doctor --json # machine-readable; non-zero exit on any FAIL
Abridged sample output:
Install / Extras¶
OpenMed ships a small permissive core and keeps heavy or platform-specific stacks behind optional extras declared in pyproject.toml. If you call a feature whose extra is not installed, you get an ImportError/ModuleNotFoundError or a MissingDependencyError (a subclass of ImportError) whose message names the fix.
ModuleNotFoundError: No module named 'transformers' — the model runtime is missing¶
Symptom. Loading a model or calling analyze_text, extract_pii, or deidentify on a Hub model fails with a missing transformers import, or you see:
Cause. The core install does not pull in the Hugging Face runtime. The Transformers/tokenizers/accelerate stack lives in the hf extra. The extra does not choose a PyTorch build for you; install the CPU, CUDA, or MPS build that matches your platform separately.
Fix.
RuntimeError: No inference backend available — neither the HF nor MLX backend is installed¶
Symptom. Backend auto-detection cannot find a usable runtime:
RuntimeError: No inference backend available. Install at least one: pip install openmed[hf] or pip install openmed[mlx]
Related backend errors:
ValueError: Unknown backend 'xyz'. Available: ['hf', 'mlx']— you passed abackend=value that is not"hf"or"mlx".RuntimeError: Backend 'mlx' is not available. Install its dependencies first.— you selected a backend explicitly but its dependencies are not importable on this machine.
Cause. No inference backend is importable. hf is the portable backend after a compatible PyTorch runtime is installed; mlx is the Apple-Silicon path.
Fix. Install at least one backend. For hf, first follow the PyTorch installation instructions for your CPU/GPU platform, then install the OpenMed extra:
pip install "openmed[hf]" # portable PyTorch/Transformers backend
pip install "openmed[mlx]" # Apple Silicon MLX backend
MissingDependencyError: Optional dependency '…' is required — a feature extra is missing¶
Symptom. A capability-specific call fails with a message shaped like:
Optional dependency 'pdfplumber' is required for this operation. Install with: pip install "openmed[multimodal]".
Cause. OpenMed defers document/image intake, zero-shot NER, framework bridges, exporters, and connectors to purpose-built extras. Dependency errors include a remediation hint; the package-install commands below work from a published OpenMed installation.
Fix. Install the extra the message names. Common ones:
| Feature | Extra | Install command |
|---|---|---|
Document / image intake + OCR (pdfplumber, python-docx, Pillow, DICOM, docTR/Tesseract/EasyOCR) | multimodal | pip install "openmed[multimodal]" |
| Heavier PaddleOCR backend | ocr-paddle | pip install "openmed[ocr-paddle]" |
| Zero-shot GLiNER NER | gliner | pip install "openmed[gliner]" |
| REST service | service | pip install "openmed[service]" |
| MCP server | mcp | pip install "openmed[mcp]" |
| Optional Typer/Rich CLI | cli | pip install "openmed[cli]" |
| Apple Silicon MLX runtime | mlx | pip install "openmed[mlx]" |
| Core ML packaging | coreml | pip install "openmed[coreml]" |
| ONNX Runtime | onnx | pip install "openmed[onnx]" |
| OpenVINO runtime | openvino | pip install "openmed[openvino]" |
| pandas / polars accessors | pandas / polars | pip install "openmed[pandas]" / pip install "openmed[polars]" |
| Dask / DuckDB | dask / duckdb | pip install "openmed[dask]" / pip install "openmed[duckdb]" |
| spaCy component | spacy | pip install "openmed[spacy]" |
| Presidio bridge | presidio | pip install "openmed[presidio]" |
| Grounding (rapidfuzz) | grounding | pip install "openmed[grounding]" |
| LangChain / LlamaIndex | langchain / llamaindex | pip install "openmed[langchain]" / pip install "openmed[llamaindex]" |
| Kafka / cloud object storage | kafka / cloud | pip install "openmed[kafka]" / pip install "openmed[cloud]" |
| AWQ / GPTQ export | awq / gptq | pip install "openmed[awq]" / pip install "openmed[gptq]" |
You can stack extras: pip install "openmed[hf,service]" or pip install "openmed[hf,mlx,docs]".
TesseractNotFoundError / OCR reports no engine — the system binary is missing¶
Symptom. OCR fails even though openmed[multimodal] is installed, with a message like:
Optional dependency 'tesseract' is required for this operation. Install with: pip install "openmed[multimodal]" and install the system Tesseract binary (e.g. `brew install tesseract` or `apt-get install tesseract-ocr`).
Cause. Tesseract is a system binary that pip does not install. The Python extra provides only the pytesseract wrapper.
Fix. Install the OS package alongside the extra:
pip install "openmed[multimodal]"
brew install tesseract # macOS
sudo apt-get install tesseract-ocr # Debian/Ubuntu
docTR and EasyOCR ship inside openmed[multimodal] and need no separate system binary; PaddleOCR lives in the separate openmed[ocr-paddle] extra.
Model Download & Offline¶
ValueError: Could not load model … — download failed or the model was not found¶
Symptom. The first call that needs a model fails while resolving files from the Hugging Face Hub:
The wrapped error is whatever transformers/huggingface_hub raised — a connection timeout, an HTTP 401 on a gated repo, an HTTP 404 for a wrong id, or a proxy/TLS failure.
Cause. OpenMed downloads model artifacts on first use and keeps them in a local cache. Component-loading paths use OpenMedConfig.cache_dir (default ~/.cache/openmed); direct Hugging Face operations can also use the standard Hub cache controlled by HF_HOME / HF_HUB_CACHE. OPENMED_CACHE_DIR is read by selected data and deployment tooling, not as a generic OpenMedConfig override. Failures are usually network reachability, a proxy, or a private/gated repo needing a token.
Fix.
- Behind a proxy / corporate firewall. Export standard proxy variables before the first run:
- Using a Hub mirror. OpenMed honors the standard Hugging Face endpoint variable; point it at your mirror:
- Private or gated model. Provide a token so the Hub authorizes the download:
openmed doctor reports WARN hf_token: present=False when no token is set.
- Wrong identifier. Confirm the id (
org/model) or registry alias exists — see the Model Registry andopenmed models list.
Cold start on the first request is slow¶
Symptom. The first analyze_text / extract_pii / deidentify call takes noticeably longer than later calls.
Cause. First use downloads model artifacts, then loads weights and the tokenizer into memory. Model files remain in the filesystem cache. In-memory weights and pipelines are reused only when calls share a ModelLoader (or run through the shared REST runtime); separate top-level convenience calls can load them again.
Fix. Warm the cache and reuse loaders rather than paying the cost per call:
- Pre-download once so later runs hit the cache: call
ModelLoader.load_model()(as in the offline example below) or run a model-backed request on a machine with network before going offline. ConstructingModelLoader()by itself does not download a model. - Reuse one
ModelLoader/pipeline instead of constructing a new one per document — see ModelLoader & Pipelines. - In the REST service, pre-load models at startup with
OPENMED_SERVICE_PRELOAD_MODELSand keep them resident withOPENMED_SERVICE_KEEP_ALIVE— see REST Service.
Running offline / air-gapped, or OfflineModeError on inference¶
Symptom. You want no network calls after startup, or an operation raises:
OfflineModeError: OPENMED_OFFLINE/local_only=True blocks outbound network access after model loading. Pre-download required model files into the configured cache, pass a local model path, or disable offline mode before remote fetches. Blocked action: socket connection.
Cause. Local-only mode is active (OPENMED_OFFLINE=1 or OpenMedConfig(local_only=True)). It passes local_files_only=True to Hub loaders, sets HF_HUB_OFFLINE=1, TRANSFORMERS_OFFLINE=1, and HF_DATASETS_OFFLINE=1, and blocks outbound sockets during inference. The error means an operation tried to reach the network after the model was loaded — usually because the required files were not cached first.
Fix. Warm the cache before enabling offline mode, then turn it on:
# 1. Download once with network available (populates ~/.cache/openmed)
python -c "from openmed.core import ModelLoader; ModelLoader().load_model('disease_detection_superclinical')"
# 2. Then run strictly local
export OPENMED_OFFLINE=1
from openmed.core import ModelLoader, OpenMedConfig
config = OpenMedConfig(local_only=True) # defaults to ~/.cache/openmed
loader = ModelLoader(config=config)
You can also skip the Hub entirely by passing a local directory as model_name/model_id; OpenMed then loads with local_files_only=True so a missing tokenizer, config, or weight file fails locally instead of downloading. See Configuration & Validation and the FAQ.
Performance / Cold-start & Memory¶
High or growing memory use on long documents or batches¶
Symptom. Memory climbs when processing many documents, or a single very long document uses more memory than expected.
Cause. Each pipeline holds a model in memory, and long inputs are tokenized into large tensors. Creating a new pipeline per document multiplies resident memory.
Fix.
- Reuse one loader/pipeline across documents; do not build a fresh pipeline per call. See ModelLoader & Pipelines.
- Batch repeated work through the batch processor rather than looping one call at a time — see Batch Processing.
- Long inputs use sentence windows and tokenizer limits by default.
analyze_textenables sentence detection and groups sentences into bounded windows, while the tokenizer uses the model's maximum length (truncation=True). A single oversized sentence can still be truncated. Pass an explicitmax_lengthto bound per-request memory, or settruncation=Falseonly when you have verified the input fits. - In the REST service, bound the working set:
OPENMED_SERVICE_MAX_RESIDENT_MODELS(LRU eviction),OPENMED_SERVICE_MODEL_MEMORY_BUDGET_BYTES, andOPENMED_SERVICE_MAX_TEXT_LENGTH(defaults to 1,000,000 characters; requests above it are rejected). Use the model-lifecycle endpoints to unload models. See REST Service.
StreamingBufferError on streaming de-identification¶
Symptom. A streaming de-identification run raises:
StreamingBufferError: carry-over buffer exceeded max_buffer before any prefix could be finalized; increase max_buffer for this stream
Cause. The carry-over buffer that keeps entity spans intact across chunk boundaries grew past max_buffer before a safe prefix could be emitted — typically a very long unbroken run of text.
Fix. Increase max_buffer above the longest identifier or unsplittable text run the stream must retain. Changing the source chunk size alone does not make an overlong unsafe tail safe to emit.
Device (CPU / GPU / MLX)¶
Choosing CPU, CUDA, or Apple Silicon¶
Symptom. You want to control which device inference runs on, or a GPU is not being used.
Cause. The PyTorch device default is "auto": OpenMed probes MPS, then CUDA, then falls back to CPU. Explicit config or environment values override that choice; MLX is a separate backend and requires Apple Silicon plus the matching dependencies.
Fix. Select the device through OpenMedConfig or environment variables:
from openmed.core import OpenMedConfig, ModelLoader
config = OpenMedConfig(device="cuda") # or "cuda:1", "mps", "cpu"
loader = ModelLoader(config=config)
export OPENMED_DEVICE=cuda:1 # legacy alias
export OPENMED_TORCH_DEVICE=cuda:1 # PyTorch backend device
Set only one of those variables when possible; OPENMED_TORCH_DEVICE takes precedence over the legacy OPENMED_DEVICE. The auto-detection order is MPS → CUDA → CPU, and "gpu" is normalized to "cuda". If you request device="cuda" on a host without CUDA, PyTorch raises its standard device error (for example AssertionError: Torch not compiled with CUDA enabled or RuntimeError: No CUDA GPUs are available) — fall back to device="cpu" or install a CUDA-enabled PyTorch build. See Configuration & Validation.
Apple Silicon: MLX vs. Torch MPS¶
Symptom. You are on an Apple-Silicon Mac and want acceleration, or an MLX-only artifact fails on a non-Apple host.
Cause. MLX runs only on Apple Silicon. On other hosts, OpenMed substitutes matching PyTorch repositories for the supported privacy-filter MLX family. Other MLX-only token-classification artifacts have no general automatic fallback; select a compatible upstream PyTorch model explicitly. MLX language-model features also have no non-MLX fallback and require mlx-lm:
ImportError: mlx-lm is required for OpenMed MLX language models. Install with: pip install openmed[mlx]
Fix. On Apple Silicon, install the MLX extra and verify the backend resolves:
pip install "openmed[mlx]"
python -c "from openmed.core.backends import get_backend; print(type(get_backend()).__name__)"
For the PyTorch MPS path and its tuning defaults, see MLX Backend and Torch MPS Performance. On non-Apple hosts, keep device="cpu" or device="cuda".
Input & Language Errors¶
ValueError: Input text cannot be empty / cannot be None¶
Symptom. A call to the public API raises one of:
ValueError: Input text cannot be None
ValueError: Input text cannot be empty
ValueError: Input text too long. Maximum length: <n>
Cause. OpenMed validates inputs before inference. Empty, None, or over-length text is rejected up front so API clients get a clear error instead of a downstream crash.
Fix. Pass non-empty text; strip/guard user input before calling. If you need a length ceiling, set it explicitly with the validation helper:
from openmed.utils.validation import validate_input
# validate_input strips surrounding whitespace automatically.
text = validate_input(user_supplied_text, max_length=2000, allow_empty=False)
ValueError: Unsupported language '…'¶
Symptom. A PII call with an unrecognized lang raises:
ValueError: Unsupported language 'xx'. Supported: ['ar', 'de', 'en', 'es', 'fr', 'he', 'hi', 'id', 'it', 'ja', 'ko', 'nl', 'pt', 'ro', 'te', 'th', 'tr']
Cause. PII extraction and de-identification support 17 supported PII language codes: ar, de, en, es, fr, he, hi, id, it, ja, ko, nl, pt, ro, te, th, and tr. Passing anything outside that set (or a mistyped code) raises this error.
Fix. Use one of the supported codes with extract_pii(..., lang="<code>"). Clinical NER coverage depends on the selected registry model — check each model's languages in the Model Registry. See the FAQ.
ValueError: method must be one of … (de-identification)¶
Symptom. deidentify(..., method="…") with an unknown method raises:
ValueError: method must be one of ('mask', 'remove', 'replace', 'hash', 'shift_dates', 'format_preserve')
Cause. deidentify() accepts a fixed set of methods (default method="mask"). A typo or unsupported value is rejected.
Fix. Pick a valid method for your reversibility needs (see the FAQ and PII Anonymization):
from openmed import deidentify
# Synthetic example only; do not paste real patient text into documentation or issues.
result = deidentify("Patient John Doe, DOB 01/15/1970", method="mask")
print(result.deidentified_text) # read output from .deidentified_text (not .text)
Common de-identification gotchas
- Read results from
result.deidentified_text, notresult.text. - Redacted output is not reversible by itself. For an authorized reversible workflow, pass
keep_mapping=Trueand restore withreidentify(result.deidentified_text, result.mapping). The mapping contains raw identifiers and must be protected as PHI. Date shifts can also be reversed by someone who knows the offset. date_shift_daysrequiresmethod="shift_dates"(otherwiseValueError: date_shift_days requires method='shift_dates'), andpatient_keyrequiresdate_shift_secret(ValueError: patient_key requires date_shift_secret).- Detection is an assistive control, not a substitute for a privacy review. Always inspect output before release.
REST Service & MCP Setup¶
REST service fails to import or start¶
Symptom. Starting the API fails with ModuleNotFoundError: No module named 'fastapi' (or uvicorn).
Cause. The REST surface (fastapi, uvicorn, tracing/observability deps) lives in the service extra.
Fix. Install the extra and launch the ASGI app with uvicorn:
Tune behavior with OPENMED_SERVICE_* variables, e.g. OPENMED_PROFILE=dev, OPENMED_SERVICE_PRELOAD_MODELS, OPENMED_SERVICE_MAX_TEXT_LENGTH, and OPENMED_SERVICE_TRUSTED_HOSTS (defaults to loopback only). See REST Service, REST Authentication, and REST Tracing. Keep the loopback bind for local troubleshooting. Before exposing the service on a network, configure authentication, TLS at the ingress or reverse proxy, and an exact trusted-host allowlist.
MCP server fails to start¶
Symptom. Launching the MCP server raises:
RuntimeError: The MCP SDK is not installed. Install OpenMed with the MCP extra: pip install "openmed[mcp]"
Cause. The Model Context Protocol SDK lives in the mcp extra.
Fix. Install the extra and run the server module. It defaults to stdio transport; use streamable-http to serve over HTTP:
pip install "openmed[mcp]"
python -m openmed.mcp.server # stdio (default)
python -m openmed.mcp.server --transport streamable-http --host 127.0.0.1 --port 8081
The HTTP transport reads OPENMED_MCP_HOST (default 127.0.0.1), OPENMED_MCP_PORT (default 8081), OPENMED_MCP_PATH (default /mcp), and OPENMED_MCP_TRANSPORT (default stdio).
The optional Typer CLI reports Typer/Rich not installed¶
Symptom. Starting the optional Typer interface with python -m openmed.cli.typer_app prints:
Cause. The optional rich terminal UI depends on rich and typer, which live in the cli extra. The standard openmed command uses argparse and does not need this extra.
Fix.
Use openmed --help for the standard CLI (analyze, batch, deid, pii, audit, risk, models, config, doctor, and more).
Still stuck?¶
- Run
openmed doctorand include its output when reporting a problem. - Check the FAQ for conceptual questions (offline use, model selection, reversibility).
- Review Configuration & Validation for cache paths, device selection, profiles, and environment overrides.
- If you believe you found a bug, open an issue at maziyarpanahi/openmed with the error text, the command you ran, and your OpenMed version (
openmed doctorreports it). Use only synthetic text in reproductions, and remove patient content, reversible mappings, access tokens, credentials, and private model URLs from commands, tracebacks, logs, and screenshots before sharing them.