{"record":{"id":"0f0cf7d21d8fb2fb","repo":"mvanhorn/last30days-skill","slug":"no-sources-are-available-for-this-run","errorCode":null,"errorMessage":"No sources are available for this run.","messagePattern":"No sources are available for this run\\.","errorType":"exception","errorClass":"RuntimeError","httpStatus":null,"severity":"error","filePath":"skills/last30days/scripts/lib/pipeline.py","lineNumber":2014,"sourceCode":"    # submitted to the network executor below.\n    if corpus_requested and \"corpus\" not in excluded_sources and \"corpus\" not in available:\n        available.append(\"corpus\")\n    if web_backend == \"none\":\n        available = [s for s in available if s != \"grounding\"]\n    elif web_backend in (\"brave\", \"exa\", \"serper\", \"parallel\", \"keyless\") and \"grounding\" not in available:\n        available.append(\"grounding\")\n    if (\n        hiring_signals_mode\n        or (not requested_sources and _company_topic_likely(topic))\n    ) and \"jobs\" not in available:\n        available.append(\"jobs\")\n    if hiring_signals_mode:\n        config = dict(config)\n        config[\"_hiring_signals_mode\"] = True\n        if not requested_sources:\n            available = [\"jobs\"]\n    if not available:\n        raise RuntimeError(\"No sources are available for this run.\")\n\n    planner_requested_sources = requested_sources\n    if hiring_signals_mode and not planner_requested_sources:\n        planner_requested_sources = [\"jobs\"]\n\n    if external_plan is not None:\n        # External plan provided (e.g., from Claude Code via --plan flag).\n        # Explicit input is a contract: validate it before permissive sanitization.\n        planner.validate_external_plan(external_plan)\n        plan = planner._sanitize_plan(\n            external_plan, topic, available, planner_requested_sources, depth,\n        )\n        plan_source = \"external\"\n    else:\n        plan = planner.plan_query(\n            topic=topic,\n            available_sources=available,\n            requested_sources=planner_requested_sources,","sourceCodeStart":1996,"sourceCodeEnd":2032,"githubUrl":"https://github.com/mvanhorn/last30days-skill/blob/c7460f6114449ddfe6ea3fc2f23c3d910c0e740c/skills/last30days/scripts/lib/pipeline.py#L1996-L2032","documentation":"RuntimeError raised in run_pipeline after the available-sources list is assembled (including auto-added 'grounding' and 'jobs'). It means every candidate source was filtered out — either the caller requested sources that are all unavailable/unknown, or no source is currently available given the config (missing API keys, digg/yt-dlp binaries not on PATH, etc.). The pipeline refuses to run a sweep that could never fetch anything.","triggerScenarios":"requested_sources=['x'] with no X backend resolvable (no ScrapeCreators key, no bird session); requested_sources naming only sources whose availability check fails; hiring_signals_mode collapsing available to ['jobs'] but 'jobs' itself unavailable in a path that later intersects with requested; a mock-less run where available_sources() returns [] for every requested source.","commonSituations":"Fresh install with no credentials configured; ScrapeCreators key expired/revoked so x is unavailable; digg-pp-cli and yt-dlp not on the agent subprocess PATH (per AGENTS.md PATH gating); explicitly passing --sources with names that are all unavailable.","solutions":["Run without requested_sources to let the pipeline use whatever keyless sources are available (reddit, hackernews).","Configure credentials for the sources you want: SCRAPECREATORS_API_KEY for x/instagram, and ensure digg-pp-cli / yt-dlp are on PATH.","Check requested source names for typos; an unknown name yields no available source.","Re-run setup (python3 skills/last30days/scripts/setup_wizard or the onboarding flow) to restore missing keys."],"exampleFix":"# before: only x requested, but no key configured\nrun_pipeline(topic, requested_sources=[\"x\"], config={})\n\n# after: keyless sources, or provide the key\nrun_pipeline(topic, requested_sources=[\"reddit\", \"hackernews\"], config={\"SCRAPECREATORS_API_KEY\": key})","handlingStrategy":"validation","validationCode":"from skills.last30days.scripts.lib import pipeline\n# dry-check availability first (same helper the pipeline uses)\navail = pipeline.available_sources(config, requested_sources or None, x_pending=False)\nif not avail:\n    raise SystemExit(\"configure credentials or drop requested_sources\")","typeGuard":null,"tryCatchPattern":"try:\n    result = run_pipeline(topic, requested_sources=sources, config=config)\nexcept RuntimeError as exc:\n    if \"No sources are available\" in str(exc):\n        result = run_pipeline(topic, config=config)  # keyless defaults\n    else:\n        raise","preventionTips":["Run the setup wizard before first use so at least one keyed backend is configured.","Verify optional-source binaries (digg-pp-cli, yt-dlp) are on the subprocess PATH, not just on disk.","Call with no requested_sources when credentials are uncertain — keyless reddit/hackernews still work."],"tags":["sources","configuration","credentials","pipeline"],"backgroundTag":null,"analyzedSha":"c7460f6114449ddfe6ea3fc2f23c3d910c0e740c","analyzedAt":"2026-08-15T03:34:49.540Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}