PrefectHQ/fastmcp · error · StateFileError
The Horizon API key is invalid
Error message
The Horizon API key is invalid
What it means
CredentialStore.save validates the key by constructing AuthState; any pydantic ValidationError (e.g. empty key) is caught and converted to StateFileError('The Horizon API key is invalid') so callers get a single CLI-friendly error type instead of a pydantic traceback.
Source
Thrown at fastmcp_slim/fastmcp/cli/deploy/credentials.py:75
class CredentialStore:
"""Persist the active personal Horizon API key."""
def __init__(self, state_directory: Path | None = None) -> None:
if state_directory is None:
import fastmcp
state_directory = fastmcp.settings.home / "cli"
self.path = state_directory / "auth.json"
def load(self) -> SecretStr | None:
state = read_state(self.path, AuthState, secret=True)
return state.api_key if state is not None else None
def save(self, api_key: SecretStr | str) -> None:
try:
state = AuthState(schemaVersion=1, apiKey=api_key)
except ValidationError:
raise StateFileError("The Horizon API key is invalid") from None
write_state(
self.path,
{
"schemaVersion": state.schema_version,
"apiKey": state.api_key.get_secret_value(),
},
)
def save_for_origin(
self,
api_key: SecretStr | str,
*,
expected_api_origin: str,
) -> None:
"""Save a key only while its issuing Horizon origin is active."""
from fastmcp.cli.deploy.configuration import ConfigurationStore
expected_api_origin = normalize_api_origin(expected_api_origin)View on GitHub (pinned to 1f02114297)
Solutions
- Pass a non-empty Horizon API key string/SecretStr to save()
- Strip whitespace from the key before saving
- Re-run `fastmcp deploy login` to obtain and store a valid key
- Inspect the upstream secret source for empty values
Example fix
// before
store.save(config.get("apiKey")) # None/empty -> StateFileError
// after
key = (config.get("apiKey") or "").strip()
if key:
store.save(key) Defensive patterns
Strategy: validation
Validate before calling
key = os.environ.get("HORIZON_API_KEY", "").strip()
if not key:
raise SystemExit("HORIZON_API_KEY is not set") Type guard
def is_valid_api_key(key: str | SecretStr) -> bool:
raw = key.get_secret_value() if isinstance(key, SecretStr) else key
return bool(raw and raw.strip()) Try / catch
from fastmcp.cli.deploy.credentials import StateFileError
try:
store.save(api_key)
except StateFileError as e:
print(f"Credential not saved: {e}; re-run `fastmcp deploy login`") Prevention
- Validate the key is non-empty before calling save()
- Strip whitespace from user-pasted keys
- Source keys from a verified secret store, not possibly-empty env vars
When it happens
Trigger: Calling save (directly, via save_for_origin, or via resolve_credential) with a SecretStr or str that fails AuthState validation — most commonly empty/whitespace values.
Common situations: Login scripts reading an unset env var; pasted keys with stray whitespace; empty secrets in CI secret managers surfaced as ''.
Related errors
- The API key is empty
- At least one of 'tools', 'include_tags', or 'exclude_tags' i
- Path must be absolute
- CIMD documents cannot use shared-secret auth methods: {v}. U
- CIMD documents must include at least one redirect_uri
AI-assisted analysis of PrefectHQ/fastmcp@1f02114297 (2026-08-29).
Data as JSON: /api/errors/b79601c2f91cdb3a.
Report an issue: GitHub.