{"record":{"id":"c3d17c40d0e06cd8","repo":"ZhuLinsen/daily_stock_analysis","slug":"generated-web-index-not-found-web-index-path","errorCode":null,"errorMessage":"generated Web index not found: {WEB_INDEX_PATH}","messagePattern":"generated Web index not found: (.+?)","errorType":"exception","errorClass":"FileNotFoundError","httpStatus":null,"severity":"error","filePath":"scripts/refresh_stock_index.py","lineNumber":51,"sourceCode":"def _has_tushare_token() -> bool:\n    env_path = REPO_ROOT / \".env\"\n    try:\n        from dotenv import load_dotenv  # type: ignore\n    except ImportError:\n        if env_path.is_file():\n            for line in env_path.read_text(encoding=\"utf-8\", errors=\"ignore\").splitlines():\n                key, sep, value = line.partition(\"=\")\n                if sep and key.strip() == \"TUSHARE_TOKEN\" and value.strip().strip(\"'\\\"\"):\n                    return True\n        return bool(os.getenv(\"TUSHARE_TOKEN\", \"\").strip())\n\n    load_dotenv(env_path)\n    return bool(os.getenv(\"TUSHARE_TOKEN\", \"\").strip())\n\n\ndef _sync_static_index() -> None:\n    if not WEB_INDEX_PATH.is_file():\n        raise FileNotFoundError(f\"generated Web index not found: {WEB_INDEX_PATH}\")\n    STATIC_INDEX_PATH.parent.mkdir(parents=True, exist_ok=True)\n    shutil.copyfile(WEB_INDEX_PATH, STATIC_INDEX_PATH)\n    print(f\"[refresh_stock_index] synced {WEB_INDEX_PATH} -> {STATIC_INDEX_PATH}\", flush=True)\n\n\ndef main(argv: Sequence[str] | None = None) -> int:\n    parser = argparse.ArgumentParser(description=\"刷新股票自动补全索引\")\n    parser.add_argument(\n        \"--skip-fetch\",\n        action=\"store_true\",\n        help=\"跳过 Tushare 抓取，仅用现有 data/stock_list_*.csv 重新生成索引\",\n    )\n    args = parser.parse_args(argv)\n\n    try:\n        if args.skip_fetch:\n            print(\"[refresh_stock_index] skip Tushare fetch; using existing CSV files\")\n        else:","sourceCodeStart":33,"sourceCodeEnd":69,"githubUrl":"https://github.com/ZhuLinsen/daily_stock_analysis/blob/5159bd72e8373d215492dff122acc9d389e219c9/scripts/refresh_stock_index.py#L33-L69","documentation":"_sync_static_index copies apps/dsa-web/public/stocks.index.json (WEB_INDEX_PATH) into the static assets directory and refuses to continue if the source file does not exist. That index is itself a build artifact produced by this script's earlier generation phase (from data/stock_list_*.csv), so its absence means the generation step was skipped or failed before the sync step.","triggerScenarios":"Running refresh_stock_index.py --skip-fetch when data/stock_list_*.csv is also absent (nothing to generate the index from, so stocks.index.json is never written); running only the sync portion; the web public dir cleaned (fresh clone, git clean, or dsa-web reinstall wiping public/).","commonSituations":"First run on a fresh clone without prior fetch output; CI job or wrapper invoking the script with --skip-fetch before any successful full run; stocks.index.json gitignored so a clean checkout lacks it.","solutions":["Run the script WITHOUT --skip-fetch once so data/stock_list_*.csv is fetched and apps/dsa-web/public/stocks.index.json is generated.","If fetch must be skipped, ensure data/stock_list_*.csv already exists (from a previous run) so generation can produce the index before sync.","Check that apps/dsa-web/public/ exists and is writable; the generator writes the index there.","If TUSHARE_TOKEN gating skipped the fetch silently, set the token (see error 180) so the full run completes."],"exampleFix":"# before\n$ python scripts/refresh_stock_index.py --skip-fetch\nFileNotFoundError: generated Web index not found: .../stocks.index.json\n\n# after\n$ python scripts/refresh_stock_index.py            # full run: fetch -> generate -> sync\n$ python scripts/refresh_stock_index.py --skip-fetch  # now safe, CSVs exist","handlingStrategy":"validation","validationCode":"from scripts.refresh_stock_index import WEB_INDEX_PATH\nfrom pathlib import Path\n\nif not WEB_INDEX_PATH.is_file():\n    raise SystemExit(\"Run full refresh first (no --skip-fetch) to generate stocks.index.json\")","typeGuard":"def web_index_ready() -> bool:\n    return WEB_INDEX_PATH.is_file()","tryCatchPattern":"try:\n    _sync_static_index()\nexcept FileNotFoundError:\n    run_full_refresh()  # fetch + generate, then retry sync\n    _sync_static_index()","preventionTips":["On fresh clones, run the script once without --skip-fetch before using skip mode.","Keep data/stock_list_*.csv artifacts from a successful run for later skip-fetch use.","Ensure TUSHARE_TOKEN is set so the generation phase can actually fetch data."],"tags":["script","index","build-artifact","bootstrap"],"backgroundTag":null,"analyzedSha":"5159bd72e8373d215492dff122acc9d389e219c9","analyzedAt":"2026-08-15T01:59:36.292Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}