HKUDS/Vibe-Trading · error · Trading212ConfigError
profile must be 'paper', 'live-readonly' or 'live'
Error message
profile must be 'paper', 'live-readonly' or 'live'
What it means
Trading212Config.from_mapping validates the 'profile' key after normalization (strip + lowercase) and rejects values outside PROFILE_ENVIRONMENTS. Unlike Tiger, the default when the key is absent/empty is 'live-readonly', so this only fires for explicitly provided unknown profile strings; it fails at config-parse time before any HTTP call.
Source
Thrown at agent/src/trading/connectors/trading212/sdk.py:78
timeout: Network timeout in seconds.
readonly: Always true for built-in profiles; order methods refuse all
requests regardless of this flag.
"""
api_key: str = ""
api_secret: str = ""
profile: str = "live-readonly"
base_url: str = DEFAULT_BASE_URL
timeout: float = 15.0
readonly: bool = True
@classmethod
def from_mapping(cls, data: Mapping[str, Any] | None = None) -> "Trading212Config":
"""Build a config from a JSON-like mapping, normalizing profile/URL."""
payload = dict(data or {})
profile = str(payload.get("profile") or "live-readonly").strip().lower()
if profile not in PROFILE_ENVIRONMENTS:
raise Trading212ConfigError("profile must be 'paper', 'live-readonly' or 'live'")
base_url = str(payload.get("base_url") or DEFAULT_BASE_URL).strip().rstrip("/")
if not base_url.startswith(("http://", "https://")):
raise Trading212ConfigError("base_url must start with http:// or https://")
return cls(
api_key=str(payload.get("api_key") or "").strip(),
api_secret=str(payload.get("api_secret") or "").strip(),
profile=profile,
base_url=base_url,
timeout=float(payload.get("timeout") or 15.0),
readonly=bool(payload.get("readonly", True)),
)
def with_overrides(
self,
*,
api_key: str | None = None,
api_secret: str | None = None,
profile: str | None = None,View on GitHub (pinned to 80ffdda44c)
Solutions
- Use 'paper' for Trading212 demo accounts (not 'demo'), or 'live-readonly'/'live' for real accounts
- Remove the profile key to accept the safe default 'live-readonly'
- Fix separator variants: 'live readonly' or 'live_readonly' -> 'live-readonly'
Example fix
// before
{"profile": "demo", "api_key": "..."}
// after
{"profile": "paper", "api_key": "..."} Defensive patterns
Strategy: validation
Validate before calling
ALLOWED = {'paper', 'live-readonly', 'live'}
profile = str(data.get('profile') or 'live-readonly').strip().lower()
assert profile in ALLOWED, f"bad profile: {profile!r}"
cfg = Trading212Config.from_mapping(data) Type guard
def is_valid_t212_profile(value: object) -> bool:
return isinstance(value, str) and value.strip().lower() in {'paper', 'live-readonly', 'live'} Try / catch
try:
cfg = Trading212Config.from_mapping(raw)
except Trading212ConfigError as exc:
if 'profile' in str(exc):
raw['profile'] = 'live-readonly' # safe default
cfg = Trading212Config.from_mapping(raw)
else:
raise Prevention
- Map Trading212 'Demo' to 'paper' in any config generation code
- Use a shared profile vocabulary/enum across connectors
- Validate configs in CI with a JSON Schema enum
When it happens
Trigger: Calling Trading212Config.from_mapping (directly or via with_overrides, build_config, load_config) with 'profile' set to something like 'Demo', 'practice', 'prod', or 'read-only' (space instead of hyphen).
Common situations: Trading212's own UI calls it a 'Demo' account, so developers write 'demo' instead of 'paper'; hyphen/space variations like 'live readonly'; migrating configs between connectors with different profile vocabularies.
Understand the failure class
Background: Config validation failed: what "invalid value for {key}" and settings-rejection errors mean across 19 open-source libraries — this error's family across 19 libraries.
Related errors
- profile must be 'paper', 'live-readonly' or 'live'
- profile must be 'paper', 'live-readonly' or 'live'
- profile must be 'paper', 'live-readonly' or 'live'
- base_url must start with http:// or https://
- group_message_buffer_size must be > 0
AI-assisted analysis of HKUDS/Vibe-Trading@80ffdda44c (2026-08-28).
Data as JSON: /api/errors/b9cf6689cc3a50fd.
Report an issue: GitHub.