PrefectHQ/fastmcp · error · ValueError
host_origin_protection must be True, False, or 'auto'.
Error message
host_origin_protection must be True, False, or 'auto'.
What it means
create_streamable_http_app validates the host_origin_protection flag against the allowed values True, False, and 'auto' (where 'auto' enables DNS-rebinding protection only for non-localhost binds). Any other value raises ValueError before middleware is assembled.
Source
Thrown at fastmcp_slim/fastmcp/server/http.py:650
else:
# No auth required
http_methods = ["POST", "DELETE"] if stateless_http else None
server_routes.append(
Route(
streamable_http_path,
endpoint=streamable_http_app,
methods=http_methods,
)
)
# Add custom routes with lowest precedence
if routes:
server_routes.extend(routes)
server_routes.extend(server._get_additional_http_routes())
# Add middleware
if host_origin_protection not in (True, False, "auto"):
raise ValueError("host_origin_protection must be True, False, or 'auto'.")
if host_origin_protection is not False:
server_middleware.insert(
0,
Middleware(
HostOriginGuardMiddleware,
allowed_hosts=allowed_hosts,
allowed_origins=allowed_origins,
mode="strict" if host_origin_protection is True else "auto",
),
)
if middleware:
server_middleware.extend(middleware)
# Create a lifespan manager to start and stop the session manager
@asynccontextmanager
async def lifespan(app: Starlette) -> AsyncGenerator[None, None]:
streamable_http_app.session_manager = FastMCPStreamableHTTPSessionManager(View on GitHub (pinned to 1f02114297)
Solutions
- Coerce config values to bool before passing: host_origin_protection = raw in (True, 'true', '1') or raw == 'auto' and 'auto'.
- Pass exactly True, False, or 'auto' (lowercase string) as the argument.
- Normalize env/YAML strings: value = {'true': True, 'false': False}.get(str(raw).lower(), 'auto') when raw is a string.
- Omit the argument to use the default instead of passing None.
Example fix
// before
app = server.http_app(host_origin_protection="true") # ValueError
// after
raw = os.getenv("HOST_ORIGIN_PROTECTION", "auto")
hop = {"true": True, "false": False}.get(raw.lower(), "auto")
app = server.http_app(host_origin_protection=hop) Defensive patterns
Strategy: validation
Validate before calling
RAW = os.getenv("HOST_ORIGIN_PROTECTION", "auto")
value = {"true": True, "false": False}.get(str(RAW).lower(), "auto")
assert value in (True, False, "auto") Type guard
def is_valid_hop(v) -> bool:
return v is True or v is False or v == "auto" Try / catch
try:
app = server.http_app(host_origin_protection=raw)
except ValueError:
app = server.http_app(host_origin_protection="auto") Prevention
- Coerce string config/env values to bool before passing the flag
- Only pass the literal True, False, or 'auto'
- Add a config-load unit test covering all three accepted values
When it happens
Trigger: Calling server.create_streamable_http_app(host_origin_protection=...) or http_app(...) with a truthy/falsy non-boolean like a string 'true', 'yes', 1, or None.
Common situations: Config-driven deployments where the setting is parsed from YAML/env as a string ('false' is neither True/False/'auto'); typos like 'Auto'; passing CLI string flags without coercion.
Understand the failure class
Background: "Invalid value" and "allowed values are" config errors: what your library rejected and how to fix it — this error's family across 41 libraries.
Related errors
- mode must be 'legacy', 'auto', or one of {list(MODERN_PROTOC
- a custom cache store requires CacheConfig.target_id for Fast
- ClientGroup requires at least one client
- Protocol mode for server {name!r} must be a string
- Missing required configuration metadata: {attr}
AI-assisted analysis of PrefectHQ/fastmcp@1f02114297 (2026-08-29).
Data as JSON: /api/errors/9a41d849fdd86cb0.
Report an issue: GitHub.