ZhuLinsen/daily_stock_analysis · error · DecisionSignalNotFoundError

not_found

not_found

Error message

Decision signal not found: {signal_id_norm}

What it means

When evaluating decision-signal outcomes, if a specific signal_id was requested but repo.list_candidate_signals returns no rows, the service raises DecisionSignalNotFoundError (a ValueError subclass, code=not_found). The API layer maps it to an HTTP 404-style error on the outcome endpoints.

Source

Thrown at src/services/decision_signal_outcome_service.py:143

                market=market_norm,
                action=action_norm,
                source_type=source_type_norm,
                statuses=statuses,
                requested_horizons=horizons_norm,
                limit=safe_limit,
            )
        else:
            signals = self.repo.list_candidate_signals(
                signal_id=signal_id_norm,
                stock_codes=stock_codes_norm,
                market=market_norm,
                action=action_norm,
                source_type=source_type_norm,
                statuses=statuses,
                limit=safe_limit,
            )
        if signal_id_norm is not None and not signals:
            raise DecisionSignalNotFoundError(f"Decision signal not found: {signal_id_norm}")

        items: List[Dict[str, Any]] = []
        created_count = 0
        updated_count = 0
        skipped_count = 0

        for signal in signals:
            for horizon in self._horizons_for_signal(signal, horizons_norm):
                existing = self.repo.get_outcome(
                    signal_id=signal.id,
                    horizon=horizon,
                    engine_version=DECISION_SIGNAL_OUTCOME_ENGINE_VERSION,
                )
                if existing is not None and not force and not self._should_recompute_outcome(existing):
                    skipped_count += 1
                    items.append(self._serialize_outcome(existing))
                    continue

View on GitHub (pinned to 5159bd72e8)

Solutions

  1. Look up valid IDs first: GET /api/v1/decision-signals (list) and use an id from the response.
  2. Verify the ID exists: check the decision_signals table / repo.get(signal_id).
  3. Call without signal_id but with stock_codes/market filters to evaluate a batch instead of one signal.

Example fix

# before
service.evaluate_outcomes(signal_id=999999)

# after
signals = service.list_signals(stock_codes=["600519"], limit=5)
service.evaluate_outcomes(signal_id=signals[0]["id"])
Defensive patterns

Strategy: try-catch

Validate before calling

signals = service.repo.list_candidate_signals(signal_id=signal_id, limit=1)
if not signals:
    return JSONResponse(status_code=404, content={"error": "not_found", "message": f"signal {signal_id} does not exist"})
outcome = service.evaluate_outcomes(signal_id=signal_id)

Try / catch

from src.services.decision_signal_service import DecisionSignalNotFoundError

try:
    outcome = service.evaluate_outcomes(signal_id=signal_id)
except DecisionSignalNotFoundError:
    return JSONResponse(status_code=404, content={"error": "not_found", "message": f"decision signal {signal_id} not found"})

Prevention

When it happens

Trigger: POST/GET /api/v1/decision-signals/outcomes (refresh/evaluate) with signal_id that does not exist in decision_signals, e.g. signal_id=999999, or an ID from a different database/environment.

Common situations: Stale signal IDs cached by a client after DB resets, IDs copied from another deployment, or deleted/deduplicated signals; also passing signal_id as a string that normalizes to a different value.

Related errors


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