{"record":{"id":"20230e2cf830acb6","repo":"nexu-io/open-design","slug":"unsupported-source-source-20230e","errorCode":null,"errorMessage":"Unsupported source: {source}","messagePattern":"Unsupported source: (.+?)","errorType":"validation","errorClass":"RuntimeError","httpStatus":null,"severity":"error","filePath":"design-templates/last30days/scripts/lib/pipeline.py","lineNumber":1012,"sourceCode":"        return pinterest.parse_pinterest_response(result), {}\n    if source == \"xiaohongshu\":\n        return xiaohongshu_api.search_feeds(\n            subquery.search_query,\n            from_date,\n            to_date,\n            env.get_xiaohongshu_api_base(config),\n            depth=depth,\n        ), {}\n    if source == \"perplexity\":\n        return perplexity.search(subquery.search_query, date_range, config, deep=config.get(\"_deep_research\", False))\n    if source == \"xquik\":\n        result = xquik.search_xquik(\n            subquery.search_query, from_date, to_date,\n            depth=depth,\n            token=env.get_xquik_token(config),\n        )\n        return xquik.parse_xquik_response(result), {}\n    raise RuntimeError(f\"Unsupported source: {source}\")\n\n\ndef _google_key(config: dict[str, Any]) -> str | None:\n    return config.get(\"GOOGLE_API_KEY\") or config.get(\"GEMINI_API_KEY\") or config.get(\"GOOGLE_GENAI_API_KEY\")\n\n\n\n\ndef _mock_stream_results(source: str, subquery: schema.SubQuery) -> tuple[list[dict], dict]:\n    payloads = {\n        \"reddit\": [\n            {\n                \"id\": \"R1\",\n                \"title\": f\"{subquery.search_query} discussion thread\",\n                \"url\": \"https://reddit.com/r/example/comments/1\",\n                \"subreddit\": \"example\",\n                \"date\": dates.get_date_range(5)[0],\n                \"engagement\": {\"score\": 120, \"num_comments\": 48, \"upvote_ratio\": 0.91},","sourceCodeStart":994,"sourceCodeEnd":1030,"githubUrl":"https://github.com/nexu-io/open-design/blob/5be4028344c2eb4c667c5a97bda8f750c5597ef7/design-templates/last30days/scripts/lib/pipeline.py#L994-L1030","documentation":"Trailing fallthrough in the stream_results dispatcher. Every source is matched by an explicit `if source == '<name>':` branch; if the source string matches none of them (reddit, x, youtube, tiktok, instagram, hackernews, bluesky, threads, truthsocial, polymarket, github, pinterest, xiaohongshu, perplexity, xquik), execution reaches the RuntimeError. It is a strict allow-list guard, not a network/auth failure.","triggerScenarios":"A SubQuery whose sources list contains a string not in the supported set (e.g. 'twitter' instead of 'x', 'medium', or a custom source name) reaches stream_results. Also triggered by typos or uppercase variants since matching is case-sensitive and lowercase only.","commonSituations":"Planner LLM emits an unsupported source name. Manual QueryPlan construction with an unvalidated source string. Renaming a source upstream without updating the planner prompt or the dispatcher.","solutions":["Check the failing source string in the error message and correct it to a supported name (use 'x' not 'twitter').","Validate SubQuery.sources against the supported-source allow-list at plan-build time rather than at retrieval time.","If you added a new source, extend the dispatch chain in pipeline.py stream_results before routing to it."],"exampleFix":"# before\nSubQuery(label='t', search_query='q', ranking_query='q', sources=['twitter'])\n\n# after\nSubQuery(label='t', search_query='q', ranking_query='q', sources=['x'])","handlingStrategy":"validation","validationCode":"SUPPORTED_SOURCES = {\n    \"reddit\", \"x\", \"youtube\", \"tiktok\", \"instagram\", \"hackernews\",\n    \"bluesky\", \"threads\", \"truthsocial\", \"polymarket\", \"github\",\n    \"pinterest\", \"xiaohongshu\", \"perplexity\", \"xquik\",\n}\n\ndef validate_sources(subquery):\n    bad = [s for s in subquery.sources if s not in SUPPORTED_SOURCES]\n    if bad:\n        raise ValueError(f\"Unsupported source(s) in subquery {subquery.label!r}: {bad}\")","typeGuard":"null","tryCatchPattern":"null","preventionTips":["Centralize the supported-source allow-list in one constant and import it in both the planner validator and the dispatcher.","Run source validation right after parsing the planner JSON, before any retrieval.","Add a unit test that asserts every source name emitted by the planner is in the allow-list."],"tags":["validation","source-dispatch","allow-list","planner"],"backgroundTag":null,"analyzedSha":"5be4028344c2eb4c667c5a97bda8f750c5597ef7","analyzedAt":"2026-08-12T12:03:58.812Z","schemaVersion":2},"datasetVersion":"2026-08-12T18:17:37.767Z"}