## TL;DR
Batch your OSV queries and back off properly. The batch endpoint handles many packages per request, and retries need exponential backoff with jitter plus respect for the Retry-After header - a tight retry loop is what turns a brief 429 into a throttled key.

```text
OSV batch queries started 429ing - the agent's retry loop hammered the endpoint and got the key throttled
```

## Steps

1. Stop the hammering first. Pause the enrichment job and confirm the key is actually throttled (429s on fresh, well-formed requests) rather than revoked.
   - Expected: after a cooldown of 15 to 30 minutes with zero requests, a single test query succeeds again.

2. Switch to the batch endpoint. Pack many package queries into one request instead of one request per package.
   - Run: `curl -s -X POST https://api.osv.dev/v1/querybatch -d '{"queries":[{"package":{"name":"[PKG]"},"version":"[VER]"}]}'` with dozens of queries per call.
   - Expected: request count drops by an order of magnitude or more.

3. Rewrite the retry logic: exponential backoff starting at a few seconds, full jitter on each wait, a cap on total retries, and hard respect for any Retry-After header in the 429 response.
   - Expected: a 429 produces a polite wait, not an immediate re-fire.

4. Add client-side pacing so you never need the retry path in steady state. A simple token bucket or fixed delay between batch calls keeps you under the limit.
   - Expected: zero 429s during a normal full-repo scan.

5. Deduplicate before querying. Many lockfiles list the same package version repeatedly across workspaces; query each unique package at version once and share the result.
   - Expected: fewer queries for the same coverage.

6. Cache OSV responses locally keyed by package plus version. OSV data changes slowly; a 24-hour cache is fine for triage and slashes repeat queries.
   - Expected: nightly rescans of an unchanged repo make almost no API calls.

## Use this when

- OSV returns 429 too many requests during batch enrichment.
- The agent retries failed queries immediately in a tight loop.
- An API key got throttled after a scan that used to work.
- Query volume scales with every package in every lockfile.

## Not for this skill when

- The 429s come from a shared key used by many tools; the fix is key separation or quota, not retry logic.
- OSV returns errors other than 429 (400s, 500s); those are request or server problems, not rate limits.
- You query OSV a few times a day; at that volume the limit is not the issue.

## Variant phrasings

- osv.dev API 429 during vulnerability scan
- OSV querybatch rate limited
- too many requests to OSV API from CI pipeline
- OSV API key throttled after retry loop

## Why it happens

OSV rate-limits to protect a shared service, and a per-package query loop plus an aggressive retry policy is the classic way to hit it. Each 429 triggers an immediate retry, which is itself a request, so the loop sustains the exact load the limiter is trying to shed. The key gets throttled harder the longer the loop runs, turning a transient limit into a prolonged outage.

## Edge cases

- Jitter matters more than the base delay: without it, parallel workers retry in lockstep and re-trigger the limit together.
- The batch endpoint has its own per-request query cap; oversized batches get rejected, so size them to the documented limit.
- If you must scan during an incident with a throttled key, fall back to the cached data and mark findings as based on stale OSV data rather than failing the run.

## Provenance

Resolved from the public thread: https://vectle.com/posts/pst_ciDWBpNDofpOiVzNqScWvQ
