{"record":{"id":"f958214932185760","repo":"mvanhorn/last30days-skill","slug":"serper-api-key-is-required-when-web-backend-serpe","errorCode":null,"errorMessage":"SERPER_API_KEY is required when web_backend='serper'","messagePattern":"SERPER_API_KEY is required when web_backend='serper'","errorType":"validation","errorClass":"RuntimeError","httpStatus":null,"severity":"error","filePath":"skills/last30days/scripts/lib/grounding.py","lineNumber":264,"sourceCode":"            backend = \"keyless\"\n        else:\n            return [], {}\n    items: list[dict] = []\n    artifact: dict = {}\n    if backend == \"brave\":\n        key = config.get(\"BRAVE_API_KEY\")\n        if not key:\n            raise RuntimeError(\"BRAVE_API_KEY is required when web_backend='brave'\")\n        items, artifact = brave_search(query, date_range, key)\n    elif backend == \"exa\":\n        key = config.get(\"EXA_API_KEY\")\n        if not key:\n            raise RuntimeError(\"EXA_API_KEY is required when web_backend='exa'\")\n        items, artifact = exa_search(query, date_range, key)\n    elif backend == \"serper\":\n        key = config.get(\"SERPER_API_KEY\")\n        if not key:\n            raise RuntimeError(\"SERPER_API_KEY is required when web_backend='serper'\")\n        items, artifact = serper_search(query, date_range, key)\n    elif backend == \"parallel\":\n        key = config.get(\"PARALLEL_API_KEY\")\n        if not key:\n            raise RuntimeError(\"PARALLEL_API_KEY is required when web_backend='parallel'\")\n        items, artifact = parallel_search(query, date_range, key)\n    elif backend == \"keyless\":\n        items, artifact = web_search_keyless.keyless_search(query, date_range, config)\n    elif backend != \"none\":\n        raise ValueError(f\"Unsupported web backend: {backend!r}\")\n    else:\n        return [], {}\n    if items and not _reddit_excluded(config):\n        # Reddit enrichment is a best-effort secondary fetch on already-retrieved\n        # web results. Isolate its HTTP failures in a throwaway capture sink so a\n        # reddit.com fetch failure (e.g. a 403 on a datacenter IP) is not\n        # attributed to the web/grounding source itself — which would otherwise\n        # discard the successfully retrieved results and report the source failed.","sourceCodeStart":246,"sourceCodeEnd":282,"githubUrl":"https://github.com/mvanhorn/last30days-skill/blob/c7460f6114449ddfe6ea3fc2f23c3d910c0e740c/skills/last30days/scripts/lib/grounding.py#L246-L282","documentation":"Raised by grounding.py when web_backend resolves to 'serper' but SERPER_API_KEY is not present in the config dict. Like the other paid-key backends, serper is only ever entered by explicit selection, so the dispatcher treats a missing key as a configuration error (RuntimeError) instead of degrading to no results.","triggerScenarios":"web_backend='serper' with SERPER_API_KEY unset/empty; key present only in the interactive shell but the engine is spawned by an agent gateway with a limited PATH/env; stale .env cached from before the key was added.","commonSituations":"User copies a recommended config that names serper.dev but never registers a key; the .env was written to the wrong directory (not ~/.config/last30days or LAST30DAYS_STORE); a typo like SERPER_KEY.","solutions":["Add SERPER_API_KEY to the environment or last30days .env and re-run.","If the key is not available, remove the explicit web_backend setting and let automatic resolution choose an available backend.","Double-check spelling: it must be SERPER_API_KEY exactly."],"exampleFix":"# before\n# .env has SERPER_KEY=...\n\n# after\n# .env has SERPER_API_KEY=<your-key>","handlingStrategy":"validation","validationCode":"config = load_config()\nif config.get(\"web_backend\") == \"serper\":\n    assert config.get(\"SERPER_API_KEY\"), \"SERPER_API_KEY must be set for serper backend\"","typeGuard":null,"tryCatchPattern":"try:\n    grounding.web_search_with_backend(query, config)\nexcept RuntimeError as e:\n    if 'SERPER_API_KEY' in str(e):\n        # fix env spelling (SERPER_API_KEY, not SERPER_KEY) or unset the backend\n        ...","preventionTips":["Check the exact spelling SERPER_API_KEY when setup fails.","Keep one .env as the single source of backend + key pairs; do not split across files.","Test with a trivial query right after configuring a new backend."],"tags":["config","api-key","web-search","serper"],"backgroundTag":null,"analyzedSha":"c7460f6114449ddfe6ea3fc2f23c3d910c0e740c","analyzedAt":"2026-08-15T03:34:49.540Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}