# Gitea Gotchas ## `/login` returns 404 — use Basic Auth or `/users//access_tokens` Symptom: hitting `/api/v1/login` (or any `/login`-style endpoint) returns `404 Not Found`. Easy to mistake for a misconfigured Gitea instance. Fix: Gitea has no session-login API endpoint. Either (a) use HTTP Basic Auth directly against any `/api/v1/` endpoint with `auth=("user","pass")` in `httpx`/`requests`, or (b) create an access token by POSTing to `/api/v1/users//access_tokens` (also Basic-Auth'd). Bearer token auth is supported on subsequent calls *after* you have a token. ## API access tokens require HTTP Basic Auth, not Bearer Symptom: Bearer token auth (`Authorization: Bearer `) returns `401 Unauthorized` even with a valid access token against Gitea API endpoints used for token creation. Fix: use `httpx.get(url, auth=("user","pass"))` (Basic Auth) for token-creation calls. Once you hold a personal access token, subsequent API calls accept it as the `password` half of Basic Auth (with the username as the user) — still NOT Bearer-style. Encode this in any helper library wrapping the Gitea API. ## PR state `closed` with `merged: true` means merged, not abandoned Symptom: PR appears `state: closed` in the API response; easy to assume the PR was cancelled. Fix: always check `merged` alongside `state`. Gitea encodes merged PRs as `state: closed, merged: true`. Parse both fields. When verifying a PR's outcome programmatically, dump the full JSON (`json.dumps(..., indent=2)`) and read both rather than asserting on `state` alone. ## Fork actions run on the fork, not the parent Symptom: A workflow file lives on a fork repo and you expect the parent repo's Actions runner to see it — or vice versa. The workflow never fires (or fires on the wrong runner). Fix: Gitea Actions is enabled per-repo. `has_actions=true` on the parent does NOT propagate to forks — forks must enable Actions independently. Fork-cleanup workflows must be committed to the fork's own `.gitea/workflows/` and run on the fork. Parent-repo workflows ignore fork branches entirely.