dolthub / dolthub/dolthub-issues
REST API: PR merge endpoint doesn't update PR state + case-sensitive auth header parsing
- Dominant language
- No language data
- Stars
- 5
- Forks
- 0
- PR merge metrics
- No merged PRs in 30d
Description
## Summary
Two bugs in the DoltHub REST API (`https://www.dolthub.com/api/v1alpha1`) related to pull request management:
1. **`POST /pulls/{id}/merge` returns `Success` but leaves the PR state as `Open`** — the data is merged to the target branch, but the PR is never marked as "Merged". Waiting indefinitely does not help; the async job completes but the state never transitions.
2. **`PATCH /pulls/{id}` rejects `Content-Type` (capital C) with `"invalid authorization header"`** — the same request succeeds with `content-type` (lowercase). HTTP headers are case-insensitive per [RFC 7230 §3.2](https://datatracker.ietf.org/doc/html/rfc7230#section-3.2), so the `authorization` header should be parsed regardless of other headers' casing.
## Steps to Reproduce
### Bug 1: Merge doesn't update PR state
```bash
# 1. Confirm PR is Open
curl -s "https://www.dolthub.com/api/v1alpha1/hop/wl-commons/pulls/166"
# → {"state": "Open", ...}
# 2. Merge via API
curl -s -X POST "https://www.dolthub.com/api/v1alpha1/hop/wl-commons/pulls/166/merge" \
-H "authorization: token $DOLTHUB_TOKEN"
# → {"status": "Success", "operation_name": "repositoryOwners/hop/repositories/wl-commons/jobs/...", ...}
# 3. Wait any amount of time, then check state
curl -s "https://www.dolthub.com/api/v1alpha1/hop/wl-commons/pulls/166"
# → {"state": "Open", ...} ← BUG: should be "Merged"
```
The data IS merged (the target branch's main contains the PR's commits), but the PR object never transitions to "Merged".
### Bug 2: Case-sensitive header parsing breaks auth
```bash
# With "Content-Type" (capital C) — FAILS
curl -s -X PATCH "https://www.dolthub.com/api/v1alpha1/hop/wl-commons/pulls/166" \
-H "authorization: token $DOLTHUB_TOKEN" \
-H "Content-Type: application/json" \
-d '{"state": "closed"}'
# → {"status": "Error", "message": "invalid authorization header"}
# With "content-type" (lowercase) — SUCCEEDS
curl -s -X PATCH "https://www.dolthub.com/api/v1alpha1/hop/wl-commons/pulls/166" \
-H "authorization: token $DOLTHUB_TOKEN" \
-H "content-type: application/json" \
-d '{"state": "closed"}'
# → {"status": "Success", "state": "Closed"}
```
Note: The `POST /merge` endpoint also exhibits this behavior — it only works without the `Content-Type` header or with lowercase `content-type`.
## Reproduction Script
```bash
#!/usr/bin/env bash
# Prerequisites: DOLTHUB_TOKEN, an open PR on a repo you have write access to
# Usage: DOLTHUB_TOKEN=dhat.v1.xxx UPSTREAM=org/repo PR_ID=123 bash repro.sh
set -euo pipefail
API="https://www.dolthub.com/api/v1alpha1"
echo "=== Verify PR is Open ==="
curl -s "$API/$UPSTREAM/pulls/$PR_ID" | python3 -c "import json,sys; print(f'State: {json.load(sys.stdin)[\"state\"]}')"
echo "=== Merge via API ==="
curl -s -X POST "$API/$UPSTREAM/pulls/$PR_ID/merge" -H "authorization: token $DOLTHUB_TOKEN" | python3 -m json.tool
echo "=== Wait 30s for async job ==="
sleep 30
echo "=== Check state (Bug 1: still Open) ==="
curl -s "$API/$UPSTREAM/pulls/$PR_ID" | python3 -c "import json,sys; print(f'State: {json.load(sys.stdin)[\"state\"]}')"
echo "=== PATCH with Content-Type (Bug 2: auth fails) ==="
curl -s -X PATCH "$API/$UPSTREAM/pulls/$PR_ID" -H "authorization: token $DOLTHUB_TOKEN" -H "Content-Type: application/json" -d '{"state":"closed"}' | python3 -m json.tool
echo "=== PATCH with content-type (works) ==="
curl -s -X PATCH "$API/$UPSTREAM/pulls/$PR_ID" -H "authorization: token $DOLTHUB_TOKEN" -H "content-type: application/json" -d '{"state":"closed"}' | python3 -m json.tool
```
## Expected Behavior
1. After `POST /pulls/{id}/merge` returns `Success`, the PR state should transition to `"Merged"`.
2. The `authorization` header should be parsed case-insensitively, regardless of the casing of other headers like `Content-Type`.
3. `PATCH /pulls/{id}` should accept `{"state": "merged"}` to allow programmatic merging with correct state.
## Actual Behavior
1. PR state remains `"Open"` indefinitely after a successful merge. The only way to close it is via `PATCH` with `{"state": "closed"}`, which shows "Closed" (not "Merged") in the DoltHub UI.
2. Including `Content-Type: application/json` (standard casing) causes `"invalid authorization header"` errors on both `POST /merge` and `PATCH` endpoints.
3. `PATCH` with `{"state": "merged"}` returns: `"This API can only be used to close a pull request, it cannot be used for merging or opening pull requests."`
## Impact
These bugs make it impossible to programmatically merge PRs via the REST API and have them display correctly in the DoltHub UI. The workaround is:
1. Merge data via `dolt` CLI (`dolt merge` + `dolt push`)
2. Close the PR via `PATCH` with lowercase `content-type`
This results in PRs showing as "Closed" instead of "Merged", which loses the merge provenance.
## Environment
- DoltHub REST API: `https://www.dolthub.com/api/v1alpha1`
- Auth: API token (`dhat.v1.*`)
- Tested against: `hop/wl-commons` (PRs #166, #167)
- Date: 2026-03-05
Contributor guide
No contributing guide indexed for this repository
Assessment
This issue has not been assessed yet.