OpenBB-finance/OpenBB · error · OpenBBError

Invalid choice. Choose from: ['all', 'agency debts', 'mbs',

Error message

Invalid choice. Choose from: ['all', 'agency debts', 'mbs', 'cmbs']

What it means

OpenBBError from SomaHoldings.get_agency_holdings: holding_type was supplied but is not a key in AGENCY_HOLDING_TYPES (accepted: 'all', 'agency debts', 'mbs', 'cmbs'). Raised before any URL is built, so it is pure input validation — note the message is a hardcoded string, not interpolated, so it always shows the same list.

Source

Thrown at openbb_platform/providers/federal_reserve/openbb_federal_reserve/utils/ny_fed_api.py:470

        response: dict = {}
        url: str = ""
        dates = await self.get_as_of_dates()
        if as_of is not None:
            as_of = get_nearest_date(dates, as_of)
        if as_of is None:
            as_of = dates[0]
        if wam is True:
            url = _get_endpoints(
                date=as_of,
            )[
                "soma_holdings"
            ]["agency_debts"]
            response = await fetch_data(url)
            return [response.get("soma", {})]
        url = _get_endpoints(date=as_of)["soma_holdings"]["get_as_of"]
        if holding_type is not None:
            if holding_type not in AGENCY_HOLDING_TYPES:
                raise OpenBBError(
                    "Invalid choice. Choose from: ['all', 'agency debts', 'mbs', 'cmbs']"
                )
            url = _get_endpoints(
                agency_holding_type=AGENCY_HOLDING_TYPES[holding_type], date=as_of
            )["soma_holdings"]["get_holding_type"]
        if cusip is not None:
            url = _get_endpoints(cusips=cusip)["soma_holdings"]["get_cusip"]
        response = await fetch_data(url)
        holdings = response.get("soma", {}).get("holdings", [])
        if not holdings:
            raise EmptyDataError()

        return holdings

    async def get_treasury_holdings(  # pylint: disable=R0917
        self,
        as_of: str | None = None,
        cusip: str | None = None,

View on GitHub (pinned to 3e071fcc2c)

Solutions

  1. Use exactly one of: 'all', 'agency debts', 'mbs', 'cmbs' (lowercase, spaces not underscores).
  2. Normalize input: strip and lowercase, then check membership in the accepted set before calling.
  3. Pass holding_type=None to get all holdings unfiltered.

Example fix

// before
holdings = await SomaHoldings().get_agency_holdings(holding_type='agency_debts')
// after
holdings = await SomaHoldings().get_agency_holdings(holding_type='agency debts')
Defensive patterns

Strategy: validation

Validate before calling

AGENCY_HOLDING_TYPES = {'all', 'agency debts', 'mbs', 'cmbs'}
holding_type = holding_type.strip().lower() if holding_type else None
assert holding_type is None or holding_type in AGENCY_HOLDING_TYPES

Type guard

def is_valid_agency_holding_type(v) -> bool:
    return v is None or (isinstance(v, str) and v.strip().lower() in {'all', 'agency debts', 'mbs', 'cmbs'})

Prevention

When it happens

Trigger: Passing holding_type='agency_debts' (underscore instead of space), 'MBS' (case-sensitive lookup), 'cmo', or 'all ' (trailing space) to get_agency_holdings.

Common situations: Copy-pasting URL slugs or API query-param values instead of the human-readable labels; assuming case-insensitivity; trailing whitespace from config files.

Related errors


AI-assisted analysis of OpenBB-finance/OpenBB@3e071fcc2c (2026-08-14). Data as JSON: /api/errors/a3facd0265931224. Report an issue: GitHub.