HKUDS/Vibe-Trading · error · AlpacaConfigError

feed must be 'iex' or 'sip'

Error message

feed must be 'iex' or 'sip'

What it means

Thrown by AlpacaConfig.from_mapping when the normalized 'feed' key is not 'iex' or 'sip' (default is 'iex'). The feed selects which market-data stream Alpaca serves; IEX is free/default while SIP requires a paid subscription, so unknown feeds are rejected at config-build time.

Source

Thrown at agent/src/trading/connectors/alpaca/sdk.py:96

    """

    api_key: str = ""
    secret_key: str = ""
    profile: str = "paper"
    feed: str = "iex"
    timeout: float = 15.0
    readonly: bool = True

    @classmethod
    def from_mapping(cls, data: Mapping[str, Any] | None = None) -> "AlpacaConfig":
        """Build a config from a JSON-like mapping, normalizing the profile."""
        payload = dict(data or {})
        profile = str(payload.get("profile") or "paper").strip().lower()
        if profile not in PROFILE_ENVIRONMENTS:
            raise AlpacaConfigError("profile must be 'paper', 'live-readonly' or 'live'")
        feed = str(payload.get("feed") or "iex").strip().lower()
        if feed not in ("iex", "sip"):
            raise AlpacaConfigError("feed must be 'iex' or 'sip'")
        return cls(
            api_key=str(payload.get("api_key") or "").strip(),
            secret_key=str(payload.get("secret_key") or "").strip(),
            profile=profile,
            feed=feed,
            timeout=float(payload.get("timeout") or 15.0),
            readonly=bool(payload.get("readonly", True)),
        )

    def with_overrides(
        self,
        *,
        api_key: str | None = None,
        secret_key: str | None = None,
        profile: str | None = None,
        feed: str | None = None,
    ) -> "AlpacaConfig":
        """Return a copy with CLI/tool overrides applied."""

View on GitHub (pinned to 80ffdda44c)

Solutions

  1. Set feed to 'iex' or remove it to use the free default
  2. Set feed to 'sip' only if your Alpaca subscription includes SIP data
  3. Double-check spelling — values are lowercased and trimmed, but must match exactly
  4. Re-run after fixing the JSON config file that load_config reads

Example fix

// before
{"profile": "paper", "feed": "nasdaq"}

// after
{"profile": "paper", "feed": "iex"}
Defensive patterns

Strategy: validation

Validate before calling

VALID_FEEDS = {"iex", "sip"}
feed = str(cfg.get("feed") or "iex").strip().lower()
if feed not in VALID_FEEDS:
    raise ValueError(f"unknown feed {feed!r}; expected 'iex' or 'sip'")

Type guard

def is_valid_alpaca_feed(value: object) -> bool:
    return isinstance(value, str) and value.strip().lower() in {"iex", "sip"}

Try / catch

try:
    config = AlpacaConfig.from_mapping(data)
except AlpacaConfigError as exc:
    if "feed must be" in str(exc):
        data["feed"] = "iex"
        config = AlpacaConfig.from_mapping(data)
    else:
        raise

Prevention

When it happens

Trigger: Passing a mapping with feed set to e.g. 'SIP ' works (lowercased/trimmed) but 'sip-pro', 'otc', 'cts', or 'full' raises. Hit via load_config from a JSON file, build_config overrides, or with_overrides.

Common situations: Copying feed names from other broker APIs; assuming a paid-tier name like 'nasdaq-totalview' is supported; typos like 'ix' or 'siep'; stale docs from an older SDK version listing other feeds.

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


AI-assisted analysis of HKUDS/Vibe-Trading@80ffdda44c (2026-08-28). Data as JSON: /api/errors/a51a74b138c49c86. Report an issue: GitHub.