ZhuLinsen/daily_stock_analysis · error · ValueError
invalid direction: {direction}
Error message
invalid direction: {direction} What it means
Raised by _direction (src/services/alert_indicators.py:371) when the normalized direction string (stripped, lowercased) is not in the allowed set for that alert type: ABOVE_BELOW_DIRECTIONS (above/below) for ma_price_cross, rsi_threshold, cci_threshold, or CROSS_DIRECTIONS (bullish_cross/bearish_cross) for macd_cross, kdj_cross. Note falsy values (None, '') fall back to the per-type default, so only non-empty wrong strings trigger it.
Source
Thrown at src/services/alert_indicators.py:371
message=message,
data_timestamp=latest,
)
def _ensure_required_bars_fetchable(alert_type: str, params: Dict[str, Any]) -> Dict[str, Any]:
required_bars = compute_required_bars(alert_type, params)
if required_bars > MAX_REQUESTED_DAYS:
raise ValueError(
f"{alert_type} periods require {required_bars} bars, "
f"but at most {MAX_REQUESTED_DAYS} days can be requested"
)
return params
def _direction(value: Any, allowed: frozenset[str], *, default: str) -> str:
direction = str(value or default).strip().lower()
if direction not in allowed:
raise ValueError(f"invalid direction: {direction}")
return direction
def _int_in_range(value: Any, field_name: str, *, default: int, minimum: int = 2, maximum: int = 250) -> int:
raw_value = default if value is None or value == "" else value
try:
number = int(raw_value)
except (TypeError, ValueError) as exc:
raise ValueError(f"invalid {field_name}: {value}") from exc
if str(raw_value).strip() not in {str(number), f"{number}.0"}:
raise ValueError(f"{field_name} must be an integer")
if number < minimum or number > maximum:
raise ValueError(f"{field_name} must be between {minimum} and {maximum}")
return number
def _finite_float(value: Any, field_name: str) -> float:
try:View on GitHub (pinned to 5159bd72e8)
Solutions
- Use 'above'/'below' for ma_price_cross, rsi_threshold, cci_threshold and 'bullish_cross'/'bearish_cross' for macd_cross, kdj_cross.
- Omit direction entirely to take the per-type default (above / bullish_cross) when you do not need it.
- Fix the frontend enum/dropdown to mirror the backend sets exactly.
Example fix
// before
{ "alert_type": "macd_cross", "parameters": { "direction": "golden_cross" } }
// after
{ "alert_type": "macd_cross", "parameters": { "direction": "bullish_cross" } } Defensive patterns
Strategy: type-guard
Validate before calling
DIRECTIONS = {
'ma_price_cross': {'above','below'}, 'rsi_threshold': {'above','below'}, 'cci_threshold': {'above','below'},
'macd_cross': {'bullish_cross','bearish_cross'}, 'kdj_cross': {'bullish_cross','bearish_cross'},
}
d = str(params.get('direction') or '').strip().lower()
if d and d not in DIRECTIONS[alert_type]:
raise ValueError(f'direction must be one of {sorted(DIRECTIONS[alert_type])}') Type guard
def is_valid_direction(alert_type: str, direction) -> bool:
allowed = {'above','below'} if alert_type in ('ma_price_cross','rsi_threshold','cci_threshold') else {'bullish_cross','bearish_cross'}
d = str(direction or '').strip().lower()
return d in allowed or d == '' # '' falls back to default Try / catch
try:
normalize_indicator_parameters(alert_type, params)
except ValueError as e:
if str(e).startswith('invalid direction:'):
return bad_request(f'direction {params.get("direction")!r} not valid for {alert_type}')
raise Prevention
- Omit direction to take the safe default instead of guessing vocabulary.
- Keep one shared direction-enum constant across frontend and backend.
- Remember cross alerts use bullish_cross/bearish_cross, threshold alerts use above/below.
When it happens
Trigger: Sending direction: "up" to ma_price_cross (allowed: above|below); "bullish" or "golden_cross" to macd_cross (allowed: bullish_cross|bearish_cross); "Both" or "cross" to rsi_threshold. Case and whitespace are tolerated, wrong vocabulary is not.
Common situations: UI dropdown values drifting from backend enum ("up"/"down" vs "above"/"below"); mixing oscillator vocabulary with cross vocabulary between alert types; docs examples using shorthand.
Related errors
- unsupported alert_type for current EventMonitor runtime: {al
- unsupported technical alert_type: {alert_type}
- unsupported_alert_type
- Desktop backend origin is invalid
- Desktop window is unavailable
AI-assisted analysis of ZhuLinsen/daily_stock_analysis@5159bd72e8 (2026-08-15).
Data as JSON: /api/errors/b57d4943e6e81253.
Report an issue: GitHub.