# newsapi.org 400 bad request on the sources parameter

## TL;DR
NewsAPI.org returns 400 on the sources parameter when it is combined with country or category, which the API forbids, or when a source id is misspelled. The fix is parameter hygiene: use sources alone or country plus category, never both, and validate source ids against the sources endpoint. A 400 is always the request's fault, so read the message and fix the params instead of retrying.

## The error
```text
HTTP 400 Bad Request
{"status":"error","code":"parametersInvalid","message":"You cannot mix the sources parameter with country or category."}
```

## When this helps
- newsapi.org calls return 400 on the sources parameter
- a query builder mixes sources with country or category
- validating news API parameters
- debugging bad-request errors from news APIs

## When it doesn't
- the error is 401; that is the API key
- the error is 429; that is quota
- the source id is valid but returns no articles; that is a coverage gap, not an error

## Works with
NewsAPI.org v2 as of 2026. Parameter rules are API-side.

## Steps
### 1. Read the 400 message; it names the problem
```bash
K="apiKey"
curl -s "https://newsapi.org/v2/top-headlines?sources=bbc-news&country=us&${K}=${NEWSAPI_KEY}" -o n400.json -w "HTTP %{http_code}\n"
python3 -c "import json; print(json.load(open("n400.json"))["message"])"
```
Expected: The exact parameter complaint. NewsAPI.org's 400 messages are specific; they tell you what to change.

### 2. Use sources alone or country plus category, never mixed
```bash
K="apiKey"
curl -s "https://newsapi.org/v2/top-headlines?sources=bbc-news&${K}=${NEWSAPI_KEY}" -o n200.json -w "HTTP %{http_code}\n"
python3 -c "import json; print(json.load(open("n200.json")).get("totalResults"))"
```
Expected: HTTP 200. Dropping the country parameter unmixes the request and the call succeeds.

### 3. Validate source ids against the sources endpoint
```python
K="apiKey"
curl -s "https://newsapi.org/v2/sources?${K}=${NEWSAPI_KEY}" -o sources.json
python3 -c "import json; d=json.load(open("sources.json")); print("known sources:", len(d["sources"]))"
```
Expected: The authoritative source id list. Misspelled ids 400 too; validate before querying.

### 4. Add parameter validation to the query builder
```python
import json
def build_query(sources=None, country=None, category=None):
    if sources and (country or category):
        raise ValueError("sources cannot mix with country or category")
    return {"sources": sources, "country": country, "category": category}
print(build_query(sources="bbc-news"))
print("invalid combos raise before any HTTP call")
```
Expected: A builder that rejects bad combos locally. The 400 never reaches the network again.

## Other ways people phrase this
### newsapi sources param 400
The mixing rule. Sources stands alone.

### parametersInvalid newsapi
The error code for bad combos. Read the message; it is specific.

### newsapi bad request top-headlines
Usually the sources mix or a bad source id. Validate both.

## Why it happens
NewsAPI.org forbids combining the sources parameter with country or category because the filters overlap ambiguously. The API answers 400 with a message naming the conflict. Retrying the same params repeats the 400; the params must change.

## Edge cases
- Source ids change over time; re-validate the list periodically.
- The everything endpoint has different parameter rules than top-headlines; check both.
- Empty results with 200 are fine; 400 is the only signal of bad params.
- Log the full 400 message; it is the fastest debugging aid the API offers.

## Provenance

Resolved from the public thread: https://vectle.com/posts/pst_cn-FbCvhpbA7luO1IUxCtg
