ZhuLinsen/daily_stock_analysis · error · ValueError

invalid analysis_phase: {requested}. Must be one of {sorted(

Error message

invalid analysis_phase: {requested}. Must be one of {sorted(_SUPPORTED_ANALYSIS_PHASES)}

What it means

Trading-calendar phase resolver (_coerce/normalize step in src/core/trading_calendar.py): analysis_phase is normalized (MarketPhase enum value, else str().strip().lower(), defaulting 'auto'; legacy analysis_intent is honored when phase is 'auto') and must be one of _SUPPORTED_ANALYSIS_PHASES = {auto, premarket, intraday, postmarket}. Any other string is rejected with the allowed list embedded, because downstream market-phase context building branches on exactly these phases.

Source

Thrown at src/core/trading_calendar.py:508

    return None, None, False


def _normalize_analysis_phase(
    analysis_phase: Optional[str],
    analysis_intent: Optional[str],
) -> str:
    def _coerce(value: Optional[str]) -> str:
        if isinstance(value, MarketPhase):
            return value.value
        return str(value or "").strip().lower()

    requested = _coerce(analysis_phase) or "auto"
    legacy_intent = _coerce(analysis_intent)
    if requested == "auto" and legacy_intent and legacy_intent != "auto":
        requested = legacy_intent
    if requested not in _SUPPORTED_ANALYSIS_PHASES:
        raise ValueError(
            f"invalid analysis_phase: {requested}. "
            f"Must be one of {sorted(_SUPPORTED_ANALYSIS_PHASES)}"
        )
    return requested


def build_market_phase_context(
    *,
    market: Optional[str],
    current_time: Optional[datetime] = None,
    trigger_source: str = "system",
    analysis_intent: str = "auto",
    analysis_phase: str = "auto",
) -> MarketPhaseContext:
    """
    Build a JSON-safe runtime market-phase context for analysis plumbing.

    ``analysis_phase="auto"`` keeps calendar inference. Explicit supported

View on GitHub (pinned to 5159bd72e8)

Solutions

  1. Use one of the supported tokens exactly: auto, premarket, intraday, postmarket (lowercase after normalization; the error lists them sorted).
  2. If you intended the legacy intent axis, pass analysis_intent only when phase is 'auto', and use phase-supported vocabulary.
  3. Map custom labels to canonical phases at your call site before invoking the calendar API.

Example fix

# before
build_market_phase_context(market="US", analysis_phase="pre-market")

# after
build_market_phase_context(market="US", analysis_phase="premarket")
Defensive patterns

Strategy: type-guard

Validate before calling

from src.core.trading_calendar import _SUPPORTED_ANALYSIS_PHASES

phase = (analysis_phase or "auto").strip().lower()
assert phase in _SUPPORTED_ANALYSIS_PHASES, f"bad phase: {phase}"

Type guard

SUPPORTED = {"auto", "premarket", "intraday", "postmarket"}

def is_analysis_phase(value: str) -> bool:
    return value.strip().lower() in SUPPORTED

Try / catch

try:
    ctx = build_market_phase_context(market="US", analysis_phase=phase)
except ValueError as exc:
    logger.error("bad analysis_phase: %s", exc)
    phase = "auto"
    ctx = build_market_phase_context(market="US", analysis_phase=phase)

Prevention

When it happens

Trigger: Calling build_market_phase_context (or the resolver it fronts) with analysis_phase like 'pre-market', 'PRE', 'overnight', 'close', or a typo; also triggered by legacy analysis_intent values that are not phase names when phase is auto. MarketPhase enum instances pass via .value.

Common situations: Env/CLI passing a human label instead of the canonical token; new phase names added by callers before the engine supports them; mixing up analysis_intent vocabulary (e.g. 'daily') with phase vocabulary.

Related errors


AI-assisted analysis of ZhuLinsen/daily_stock_analysis@5159bd72e8 (2026-08-15). Data as JSON: /api/errors/be1cc6a94c8648d2. Report an issue: GitHub.