{"record":{"id":"c46c043e233cf012","repo":"mvanhorn/last30days-skill","slug":"reddit-primary-and-fallback-produced-no-results-af","errorCode":null,"errorMessage":"Reddit primary and fallback produced no results after failure: {failure}","messagePattern":"Reddit primary and fallback produced no results after failure: (.+?)","errorType":"exception","errorClass":"SourceRunError","httpStatus":null,"severity":"error","filePath":"skills/last30days/scripts/lib/pipeline.py","lineNumber":4126,"sourceCode":"                            state,\n                            f\"Reddit primary failed; public fallback returned \"\n                            f\"{len(public_results)} items: {primary_failure}\",\n                        )\n                    return public_results, {}\n                sys.stderr.write(\n                    \"[Reddit] Public fallback returned no items after \"\n                    \"ScrapeCreators primary miss\\n\"\n                )\n            except Exception as exc:\n                public_failure = exc\n                sys.stderr.write(\n                    f\"[Reddit] Public fallback also failed \"\n                    f\"({type(exc).__name__}: {exc})\\n\"\n                )\n            failure = public_failure or primary_failure\n            if failure is not None:\n                state = reddit.classify_run_failure(str(failure))\n                raise SourceRunError(\n                    f\"Reddit primary and fallback produced no results after failure: {failure}\",\n                    state,\n                )\n            return [], {}\n\n        # Default: public Reddit first (free). ScrapeCreators backfills when the\n        # free path is empty OR returns fewer than the configured thinness floor\n        # (env.REDDIT_SC_MIN_ITEMS_VAR, default 0 = empty-only — today's\n        # behavior, no extra credit spend unless the user opts in).\n        try:\n            min_items = int(config.get(env.REDDIT_SC_MIN_ITEMS_VAR) or 0)\n        except (TypeError, ValueError):\n            min_items = 0\n        public_results: list[dict] = []\n        public_failure: Exception | None = None\n        try:\n            public_results = reddit_public.search_reddit_public(\n                reddit_query, from_date, to_date, depth=depth,","sourceCodeStart":4108,"sourceCodeEnd":4144,"githubUrl":"https://github.com/mvanhorn/last30days-skill/blob/c7460f6114449ddfe6ea3fc2f23c3d910c0e740c/skills/last30days/scripts/lib/pipeline.py#L4108-L4144","documentation":"SourceRunError raised in the Reddit fetch path when ScrapeCreators was the primary (keyed) strategy: the primary call failed AND the public fallback either failed or returned nothing, so failure = public_failure or primary_failure. The error carries a failure state from reddit.classify_run_failure (e.g. AUTH_FAILED, RATE_LIMITED) so callers can react to the class of failure, not just the message. Both the paid and free Reddit paths are exhausted — no data can be returned for this subquery.","triggerScenarios":"SCRAPECREATORS_API_KEY present and reddit resolves to the ScrapeCreators primary; ScrapeCreators raises (401/429/5xx); the code then tries reddit_public.search_reddit_public as fallback; that also raises (network down, Reddit blocking) or returns [] — with a failure recorded, SourceRunError is raised with the combined state.","commonSituations":"Expired or revoked ScrapeCreators key plus Reddit public endpoints blocked/rate-limited from the host IP; total network outage; Reddit rate limiting during heavy bursts; ScrapeCreators quota exhausted while Reddit public search is also throttled.","solutions":["Inspect the embedded failure state (SourceRunError.state / classify_run_failure) — AUTH_FAILED means fix the ScrapeCreators key, RATE_LIMITED means back off and retry.","Verify the ScrapeCreators key works: curl the API with a minimal request and check the HTTP status.","If Reddit public is IP-blocked, wait or route via a different network; the public fallback is free but not guaranteed.","Retry the run after the transient condition clears; this error is per-source, so other sources may still succeed if you let the pipeline continue."],"exampleFix":"# before\nitems, meta = fetch_reddit(subquery, ...)\n\n# after\ntry:\n    items, meta = fetch_reddit(subquery, ...)\nexcept SourceRunError as exc:\n    if exc.state == \"AUTH_FAILED\":\n        log(\"Reddit credentials invalid; skipping source\")\n    raise_if_no_sources_left(exc)","handlingStrategy":"retry","validationCode":null,"typeGuard":null,"tryCatchPattern":"try:\n    items, meta = fetch_reddit(...)\nexcept SourceRunError as exc:\n    if exc.state == \"AUTH_FAILED\":\n        raise  # credentials are broken; retrying will not help\n    time.sleep(backoff)\n    items, meta = fetch_reddit(...)  # one retry for RATE_LIMITED / transient","preventionTips":["Monitor ScrapeCreators quota and key validity (check API status codes, not by printing the key).","Add jittered backoff around source fetches in your orchestrator.","Treat SourceRunError.state as the routing signal: AUTH_* = fix creds, RATE_* = back off, else propagate."],"tags":["reddit","network","api-key","rate-limit","source-failure"],"backgroundTag":null,"analyzedSha":"c7460f6114449ddfe6ea3fc2f23c3d910c0e740c","analyzedAt":"2026-08-15T03:34:49.540Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}