{"record":{"id":"07f431f497340c8f","repo":"ZhuLinsen/daily_stock_analysis","slug":"not-found-07f431","errorCode":"not_found","errorMessage":"Decision signal not found: {signal_id_norm}","messagePattern":"Decision signal not found: (.+?)","errorType":"http","errorClass":"DecisionSignalNotFoundError","httpStatus":404,"severity":"error","filePath":"src/services/decision_signal_outcome_service.py","lineNumber":143,"sourceCode":"                market=market_norm,\n                action=action_norm,\n                source_type=source_type_norm,\n                statuses=statuses,\n                requested_horizons=horizons_norm,\n                limit=safe_limit,\n            )\n        else:\n            signals = self.repo.list_candidate_signals(\n                signal_id=signal_id_norm,\n                stock_codes=stock_codes_norm,\n                market=market_norm,\n                action=action_norm,\n                source_type=source_type_norm,\n                statuses=statuses,\n                limit=safe_limit,\n            )\n        if signal_id_norm is not None and not signals:\n            raise DecisionSignalNotFoundError(f\"Decision signal not found: {signal_id_norm}\")\n\n        items: List[Dict[str, Any]] = []\n        created_count = 0\n        updated_count = 0\n        skipped_count = 0\n\n        for signal in signals:\n            for horizon in self._horizons_for_signal(signal, horizons_norm):\n                existing = self.repo.get_outcome(\n                    signal_id=signal.id,\n                    horizon=horizon,\n                    engine_version=DECISION_SIGNAL_OUTCOME_ENGINE_VERSION,\n                )\n                if existing is not None and not force and not self._should_recompute_outcome(existing):\n                    skipped_count += 1\n                    items.append(self._serialize_outcome(existing))\n                    continue\n","sourceCodeStart":125,"sourceCodeEnd":161,"githubUrl":"https://github.com/ZhuLinsen/daily_stock_analysis/blob/5159bd72e8373d215492dff122acc9d389e219c9/src/services/decision_signal_outcome_service.py#L125-L161","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Look up valid IDs first: GET /api/v1/decision-signals (list) and use an id from the response.","Verify the ID exists: check the decision_signals table / repo.get(signal_id).","Call without signal_id but with stock_codes/market filters to evaluate a batch instead of one signal."],"exampleFix":"# before\nservice.evaluate_outcomes(signal_id=999999)\n\n# after\nsignals = service.list_signals(stock_codes=[\"600519\"], limit=5)\nservice.evaluate_outcomes(signal_id=signals[0][\"id\"])","handlingStrategy":"try-catch","validationCode":"signals = service.repo.list_candidate_signals(signal_id=signal_id, limit=1)\nif not signals:\n    return JSONResponse(status_code=404, content={\"error\": \"not_found\", \"message\": f\"signal {signal_id} does not exist\"})\noutcome = service.evaluate_outcomes(signal_id=signal_id)","typeGuard":null,"tryCatchPattern":"from src.services.decision_signal_service import DecisionSignalNotFoundError\n\ntry:\n    outcome = service.evaluate_outcomes(signal_id=signal_id)\nexcept DecisionSignalNotFoundError:\n    return JSONResponse(status_code=404, content={\"error\": \"not_found\", \"message\": f\"decision signal {signal_id} not found\"})","preventionTips":["Refresh cached signal IDs after DB resets or deletes.","Always source ids from the list endpoint in the same environment.","Treat 404 on this path as an id problem, not a server fault — do not retry blindly."],"tags":["decision-signal","not-found","outcome-evaluation"],"backgroundTag":null,"analyzedSha":"5159bd72e8373d215492dff122acc9d389e219c9","analyzedAt":"2026-08-15T01:59:36.292Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}