{"record":{"id":"e8210e4a582fc166","repo":"ZhuLinsen/daily_stock_analysis","slug":"candidate-context-file-not-found-path","errorCode":null,"errorMessage":"Candidate context file not found: {path}","messagePattern":"Candidate context file not found: (.+?)","errorType":"validation","errorClass":"FileNotFoundError","httpStatus":null,"severity":"error","filePath":"src/services/screening/context.py","lineNumber":350,"sourceCode":"            chunks.append(f\"# {path.name}\\n{text}\")\n    return \"\\n\\n\".join(chunks)\n\n\ndef _read_candidate_context_files(\n    paths: list[str | Path],\n    candidate_df: pd.DataFrame | None,\n) -> str:\n    if not paths or candidate_df is None or candidate_df.empty or \"code\" not in candidate_df.columns:\n        return \"\"\n\n    candidate_names, candidate_order = _candidate_maps(candidate_df)\n    candidate_codes = set(candidate_names)\n    chunks: list[tuple[int, int, str]] = []\n    row_position = 0\n    for path_like in paths:\n        path = Path(path_like)\n        if not path.is_file():\n            raise FileNotFoundError(f\"Candidate context file not found: {path}\")\n        rows = _load_candidate_context_rows(path)\n        for row in rows:\n            code = _normalize_code(row.get(\"code\", row.get(\"代码\", \"\")))\n            item = _format_candidate_context_row(row, candidate_codes, candidate_names)\n            if item:\n                chunks.append((candidate_order.get(code, len(candidate_order)), row_position, item))\n            row_position += 1\n    return \"\\n\".join(item for _, _, item in sorted(chunks))\n\n\ndef _format_candidate_context_rows(\n    rows: list[dict[str, object]],\n    candidate_df: pd.DataFrame | None,\n) -> str:\n    if not rows or candidate_df is None or candidate_df.empty or \"code\" not in candidate_df.columns:\n        return \"\"\n    candidate_names, candidate_order = _candidate_maps(candidate_df)\n    candidate_codes = set(candidate_names)","sourceCodeStart":332,"sourceCodeEnd":368,"githubUrl":"https://github.com/ZhuLinsen/daily_stock_analysis/blob/5159bd72e8373d215492dff122acc9d389e219c9/src/services/screening/context.py#L332-L368","documentation":"FileNotFoundError raised by _read_candidate_context_files: every entry in the candidate-context paths list must be an existing regular file before rows are parsed and matched against the screening candidate set. Unlike the main context reader, this runs per screening run with candidate codes; a missing file still aborts immediately.","triggerScenarios":"Passing candidate context paths (CSV/JSON/JSONL files keyed by stock code) where one path does not exist, is a directory, or is a broken symlink. The check happens before any candidate matching, so even unused files in the list abort the run.","commonSituations":"A pipeline stage that should have produced the candidate context file failed or was skipped, and screening was still invoked with its path; environment-specific output dirs differing between dev and prod; renamed artifacts after a schema change.","solutions":["Verify the upstream stage that generates the candidate context file ran successfully before invoking screening; fix or re-run it.","Validate all paths up front and fail with a clear message listing which are missing: missing = [p for p in paths if not Path(p).is_file()].","If some context files are optional, filter them out with a warning instead of passing them through.","Use explicit, environment-anchored paths (config-resolved absolute paths) rather than relative ones."],"exampleFix":"# before\nrun_screening(candidates=df, candidate_context=['out/ctx.csv'])  # aborts if missing\n\n# after: pre-validate and report all missing at once\nmissing = [p for p in map(Path, paths) if not p.is_file()]\nif missing:\n    raise FileNotFoundError(f'missing candidate context files: {missing}')","handlingStrategy":"validation","validationCode":"from pathlib import Path\nmissing = [str(p) for p in map(Path, candidate_context_paths) if not p.is_file()]\nif missing:\n    raise FileNotFoundError(f'candidate context files missing (upstream stage failed?): {missing}')","typeGuard":null,"tryCatchPattern":"try:\n    ctx = _read_candidate_context_files(paths, candidate_df)\nexcept FileNotFoundError as e:\n    # a missing artifact means the producer stage failed; re-run it, do not retry this call\n    log.error('candidate context missing: %s', e)\n    raise","preventionTips":["Make the screening run depend on successful completion of the stage that writes candidate context files.","Pre-check all artifact paths before starting an expensive screening run.","Use config-resolved absolute paths for pipeline artifacts."],"tags":["screening","candidate-context","file-not-found","pipeline"],"backgroundTag":null,"analyzedSha":"5159bd72e8373d215492dff122acc9d389e219c9","analyzedAt":"2026-08-15T01:59:36.292Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}