opendatalab/MinerU · error · HTTPException
Publicly exposed API disables *-http-client backends and ser
Error message
Publicly exposed API disables *-http-client backends and server_url by default. Rebind to 127.0.0.1 or start with --allow-public-http-client if you understand the SSRF risk.
What it means
HTTP 400 (PUBLIC_HTTP_CLIENT_DISABLED_DETAIL) raised by validate_public_http_client_request in public_http_client_policy.py: the API is bound to a public interface (not 127.0.0.1/localhost) AND --allow-public-http-client was not passed, AND the request tried to use a backend ending in '-http-client' or a non-empty server_url. This is a deliberate SSRF guard: a publicly exposed endpoint that lets callers choose an arbitrary server_url could be used to probe/attack internal network services, so http-client backends are disabled until the operator explicitly opts in.
Source
Thrown at mineru/cli/public_http_client_policy.py:37
*,
public_bind_exposed: bool,
allow_public_http_client: bool,
) -> None:
app.state.public_bind_exposed = public_bind_exposed
app.state.allow_public_http_client = allow_public_http_client
def validate_public_http_client_request(
*,
public_bind_exposed: bool,
allow_public_http_client: bool,
backend: str,
server_url: str | None,
) -> None:
if not public_bind_exposed or allow_public_http_client:
return
if backend.endswith("-http-client") or bool(server_url and server_url.strip()):
raise HTTPException(status_code=400, detail=PUBLIC_HTTP_CLIENT_DISABLED_DETAIL)
def warn_if_public_http_client_policy(
*,
service_name: str,
host: str,
allow_public_http_client: bool,
) -> None:
if not is_public_bind_host(host):
return
if allow_public_http_client:
logger.warning(
"MinerU {} is listening on {} with --allow-public-http-client enabled. "
"Requests may supply remote HTTP inference endpoints and turn the service "
"into an externally driven outbound request primitive, creating SSRF and "
"internal network probing risk.",
service_name,
host,View on GitHub (pinned to 4fe4bde114)
Solutions
- If you accept the SSRF risk and run in a trusted network, restart the API with --allow-public-http-client.
- Safer: bind to 127.0.0.1 and put an authenticating reverse proxy in front, so the policy never triggers.
- Drop server_url / '-http-client' backends from requests and use locally hosted models instead.
- Restrict at the network level (firewall/egress rules) if you must enable http-client backends publicly.
Example fix
# before uvicorn mineru.cli.fast_api:app --host 0.0.0.0 --port 8000 # POST with server_url='http://10.0.0.5:8001/vlm' -> 400 SSRF guard # after uvicorn mineru.cli.fast_api:app --host 0.0.0.0 --port 8000 --allow-public-http-client # (or) --host 127.0.0.1 behind an auth'd nginx proxy
Defensive patterns
Strategy: validation
Validate before calling
def request_allowed(public_bind_exposed: bool, allow_public_http_client: bool,
backend: str, server_url: str | None) -> bool:
if not public_bind_exposed or allow_public_http_client:
return True
return not backend.endswith('-http-client') and not (server_url and server_url.strip()) Type guard
def uses_http_client(backend: str, server_url: str | None) -> bool:
return backend.endswith('-http-client') or bool(server_url and server_url.strip()) Try / catch
r = requests.post(f'{base}/file_parse', json=payload)
if r.status_code == 400 and 'http-client' in r.text:
raise RuntimeError('SSRF guard active: bind 127.0.0.1, or restart API with --allow-public-http-client') Prevention
- Default API binds to 127.0.0.1; keep it that way behind an authenticating reverse proxy for public exposure.
- Only pass --allow-public-http-client after adding network egress controls — it reopens SSRF to your internal network.
- In containers, prefer publishing the port (-p 127.0.0.1:8000:8000) over binding 0.0.0.0 unless required.
When it happens
Trigger: Starting the API with host 0.0.0.0 (or any LAN/public address) without --allow-public-http-client, then sending a request whose backend is e.g. 'vlm-http-client' or that carries a server_url pointing at a remote VLM service; Docker deployments binding 0.0.0.0; reverse-proxied setups where the bind looks public to the policy check.
Common situations: Containerizing the API (Docker defaults to 0.0.0.0) and wondering why server_url requests suddenly 400; exposing the service on a LAN for a team; moving from localhost dev to server deployment without re-reading the flags.
Related errors
- Unsupported file type: {file_suffix}
- Invalid parse_method. Allowed values: {allowed_values}
- Invalid backend. Allowed values: {allowed_values}
- Invalid effort. Allowed values: {allowed_values}
- Language {lang} not supported. Allowed values: {allowed_valu
AI-assisted analysis of opendatalab/MinerU@4fe4bde114 (2026-08-14).
Data as JSON: /api/errors/39a4081388398e15.
Report an issue: GitHub.