---
title: "Gitea (gitea.com, self-served Swagger 2.0): spec vs live"
date: 2026-10-30
canonical: https://apidrifter.com/research/public-api-spec-drift-2026-11/gitea/
part_of: https://apidrifter.com/research/public-api-spec-drift-2026-11/
---

# Gitea (gitea.com, self-served Swagger 2.0): spec vs live

Part of [We checked 13 public APIs against their own OpenAPI specs. 9 had hard mismatches.](https://apidrifter.com/research/public-api-spec-drift-2026-11/).

## Summary

- Spec: https://gitea.com/swagger.v1.json (Swagger 2.0, converted to OpenAPI 3 before checking)
- Base URL: `https://gitea.com/api/v1`
- Run: 2026-10-30, read-only GET requests, no credentials
- Coverage: 537 operations in the spec, 40 requests sent, 19 successful, 40 operations observed
- Hard violations: 15 distinct schema locations
- Reviewer note: Confirmed: activity feed comment and user objects are null; User carries an undocumented username field. Swagger 2.0 cannot express null, so the null findings are partly a format limitation.

## Hard violations (15)

A typed client generated from the spec would break on these.

- `response-null-not-allowed` (hard, breaking) at `GET /orgs/{org}/activities/feeds > response 200 > application/json > /0/comment`
  - response body at /0/comment: value is null but the schema does not allow null (and 7 more like it)
  - Request: `GET /orgs/gitea/activities/feeds -> 200 application/json;charset=utf-8`
  - Expected: `["object"]`
  - Actual: `null`
  - If the spec is the source of truth: Return a non-null value in response body at /0/comment.
  - If the implementation is the source of truth: Allow null at paths["/orgs/{org}/activities/feeds"].get.responses["200"].content["application/json"].schema.items.properties["comment"] (add "null" to type, or nullable: true in OpenAPI 3.0).
- `response-null-not-allowed` (hard, breaking) at `GET /orgs/{org}/activities/feeds > response 200 > application/json > /6/comment/user`
  - response body at /6/comment/user: value is null but the schema does not allow null (and 1 more like it)
  - Request: `GET /orgs/gitea/activities/feeds -> 200 application/json;charset=utf-8`
  - Expected: `["object"]`
  - Actual: `null`
  - If the spec is the source of truth: Return a non-null value in response body at /6/comment/user.
  - If the implementation is the source of truth: Allow null at paths["/orgs/{org}/activities/feeds"].get.responses["200"].content["application/json"].schema.items.properties["comment"].properties["user"] (add "null" to type, or nullable: true in OpenAPI 3.0).
- `response-null-not-allowed` (hard, breaking) at `GET /repos/{owner}/{repo}/activities/feeds > response 200 > application/json > /0/comment/user`
  - response body at /0/comment/user: value is null but the schema does not allow null (and 6 more like it)
  - Request: `GET /repos/gitea/tea/activities/feeds -> 200 application/json;charset=utf-8`
  - Expected: `["object"]`
  - Actual: `null`
  - If the spec is the source of truth: Return a non-null value in response body at /0/comment/user.
  - If the implementation is the source of truth: Allow null at paths["/repos/{owner}/{repo}/activities/feeds"].get.responses["200"].content["application/json"].schema.items.properties["comment"].properties["user"] (add "null" to type, or nullable: true in OpenAPI 3.0).
- `response-null-not-allowed` (hard, breaking) at `GET /repos/{owner}/{repo}/activities/feeds > response 200 > application/json > /4/comment`
  - response body at /4/comment: value is null but the schema does not allow null (and 2 more like it)
  - Request: `GET /repos/gitea/tea/activities/feeds -> 200 application/json;charset=utf-8`
  - Expected: `["object"]`
  - Actual: `null`
  - If the spec is the source of truth: Return a non-null value in response body at /4/comment.
  - If the implementation is the source of truth: Allow null at paths["/repos/{owner}/{repo}/activities/feeds"].get.responses["200"].content["application/json"].schema.items.properties["comment"] (add "null" to type, or nullable: true in OpenAPI 3.0).
- `response-null-not-allowed` (hard, breaking) at `GET /repos/{owner}/{repo}/branches > response 200 > application/json > /0/commit/added`
  - response body at /0/commit/added: value is null but the schema does not allow null (and 9 more like it)
  - Request: `GET /repos/gitea/tea/branches -> 200 application/json;charset=utf-8`
  - Expected: `["array"]`
  - Actual: `null`
  - If the spec is the source of truth: Return a non-null value in response body at /0/commit/added.
  - If the implementation is the source of truth: Allow null at paths["/repos/{owner}/{repo}/branches"].get.responses["200"].content["application/json"].schema.items.properties["commit"].properties["added"] (add "null" to type, or nullable: true in OpenAPI 3.0).
- `response-null-not-allowed` (hard, breaking) at `GET /repos/{owner}/{repo}/branches > response 200 > application/json > /0/commit/modified`
  - response body at /0/commit/modified: value is null but the schema does not allow null (and 9 more like it)
  - Request: `GET /repos/gitea/tea/branches -> 200 application/json;charset=utf-8`
  - Expected: `["array"]`
  - Actual: `null`
  - If the spec is the source of truth: Return a non-null value in response body at /0/commit/modified.
  - If the implementation is the source of truth: Allow null at paths["/repos/{owner}/{repo}/branches"].get.responses["200"].content["application/json"].schema.items.properties["commit"].properties["modified"] (add "null" to type, or nullable: true in OpenAPI 3.0).
- `response-null-not-allowed` (hard, breaking) at `GET /repos/{owner}/{repo}/branches > response 200 > application/json > /0/commit/removed`
  - response body at /0/commit/removed: value is null but the schema does not allow null (and 9 more like it)
  - Request: `GET /repos/gitea/tea/branches -> 200 application/json;charset=utf-8`
  - Expected: `["array"]`
  - Actual: `null`
  - If the spec is the source of truth: Return a non-null value in response body at /0/commit/removed.
  - If the implementation is the source of truth: Allow null at paths["/repos/{owner}/{repo}/branches"].get.responses["200"].content["application/json"].schema.items.properties["commit"].properties["removed"] (add "null" to type, or nullable: true in OpenAPI 3.0).
- `response-null-not-allowed` (hard, breaking) at `GET /repos/{owner}/{repo}/branches > response 200 > application/json > /0/commit/verification/signer`
  - response body at /0/commit/verification/signer: value is null but the schema does not allow null (and 6 more like it)
  - Request: `GET /repos/gitea/tea/branches -> 200 application/json;charset=utf-8`
  - Expected: `["object"]`
  - Actual: `null`
  - If the spec is the source of truth: Return a non-null value in response body at /0/commit/verification/signer.
  - If the implementation is the source of truth: Allow null at paths["/repos/{owner}/{repo}/branches"].get.responses["200"].content["application/json"].schema.items.properties["commit"].properties["verification"].properties["signer"] (add "null" to type, or nullable: true in OpenAPI 3.0).
- `response-null-not-allowed` (hard, breaking) at `GET /repos/{owner}/{repo}/branches/{branch} > response 200 > application/json > /commit/added`
  - response body at /commit/added: value is null but the schema does not allow null
  - Request: `GET /repos/gitea/tea/branches/main -> 200 application/json;charset=utf-8`
  - Expected: `["array"]`
  - Actual: `null`
  - If the spec is the source of truth: Return a non-null value in response body at /commit/added.
  - If the implementation is the source of truth: Allow null at paths["/repos/{owner}/{repo}/branches/{branch}"].get.responses["200"].content["application/json"].schema.properties["commit"].properties["added"] (add "null" to type, or nullable: true in OpenAPI 3.0).
- `response-null-not-allowed` (hard, breaking) at `GET /repos/{owner}/{repo}/branches/{branch} > response 200 > application/json > /commit/modified`
  - response body at /commit/modified: value is null but the schema does not allow null
  - Request: `GET /repos/gitea/tea/branches/main -> 200 application/json;charset=utf-8`
  - Expected: `["array"]`
  - Actual: `null`
  - If the spec is the source of truth: Return a non-null value in response body at /commit/modified.
  - If the implementation is the source of truth: Allow null at paths["/repos/{owner}/{repo}/branches/{branch}"].get.responses["200"].content["application/json"].schema.properties["commit"].properties["modified"] (add "null" to type, or nullable: true in OpenAPI 3.0).
- `response-null-not-allowed` (hard, breaking) at `GET /repos/{owner}/{repo}/branches/{branch} > response 200 > application/json > /commit/removed`
  - response body at /commit/removed: value is null but the schema does not allow null
  - Request: `GET /repos/gitea/tea/branches/main -> 200 application/json;charset=utf-8`
  - Expected: `["array"]`
  - Actual: `null`
  - If the spec is the source of truth: Return a non-null value in response body at /commit/removed.
  - If the implementation is the source of truth: Allow null at paths["/repos/{owner}/{repo}/branches/{branch}"].get.responses["200"].content["application/json"].schema.properties["commit"].properties["removed"] (add "null" to type, or nullable: true in OpenAPI 3.0).
- `response-null-not-allowed` (hard, breaking) at `GET /repos/{owner}/{repo}/branches/{branch} > response 200 > application/json > /commit/verification/signer`
  - response body at /commit/verification/signer: value is null but the schema does not allow null
  - Request: `GET /repos/gitea/tea/branches/main -> 200 application/json;charset=utf-8`
  - Expected: `["object"]`
  - Actual: `null`
  - If the spec is the source of truth: Return a non-null value in response body at /commit/verification/signer.
  - If the implementation is the source of truth: Allow null at paths["/repos/{owner}/{repo}/branches/{branch}"].get.responses["200"].content["application/json"].schema.properties["commit"].properties["verification"].properties["signer"] (add "null" to type, or nullable: true in OpenAPI 3.0).
- `response-null-not-allowed` (hard, breaking) at `GET /repos/{owner}/{repo}/commits > response 200 > application/json > /0/commit/verification/signer`
  - response body at /0/commit/verification/signer: value is null but the schema does not allow null (and 9 more like it)
  - Request: `GET /repos/gitea/tea/commits -> 200 application/json;charset=utf-8`
  - Expected: `["object"]`
  - Actual: `null`
  - If the spec is the source of truth: Return a non-null value in response body at /0/commit/verification/signer.
  - If the implementation is the source of truth: Allow null at paths["/repos/{owner}/{repo}/commits"].get.responses["200"].content["application/json"].schema.items.properties["commit"].properties["verification"].properties["signer"] (add "null" to type, or nullable: true in OpenAPI 3.0).
- `response-null-not-allowed` (hard, breaking) at `GET /repos/{owner}/{repo}/commits/{ref}/status > response 200 > application/json > /statuses/0/creator`
  - response body at /statuses/0/creator: value is null but the schema does not allow null (and 1 more like it)
  - Request: `GET /repos/gitea/tea/commits/main/status -> 200 application/json;charset=utf-8`
  - Expected: `["object"]`
  - Actual: `null`
  - If the spec is the source of truth: Return a non-null value in response body at /statuses/0/creator.
  - If the implementation is the source of truth: Allow null at paths["/repos/{owner}/{repo}/commits/{ref}/status"].get.responses["200"].content["application/json"].schema.properties["statuses"].items.properties["creator"] (add "null" to type, or nullable: true in OpenAPI 3.0).
- `response-null-not-allowed` (hard, breaking) at `GET /repos/{owner}/{repo}/commits/{ref}/statuses > response 200 > application/json > /0/creator`
  - response body at /0/creator: value is null but the schema does not allow null (and 5 more like it)
  - Request: `GET /repos/gitea/tea/commits/main/statuses -> 200 application/json;charset=utf-8`
  - Expected: `["object"]`
  - Actual: `null`
  - If the spec is the source of truth: Return a non-null value in response body at /0/creator.
  - If the implementation is the source of truth: Allow null at paths["/repos/{owner}/{repo}/commits/{ref}/statuses"].get.responses["200"].content["application/json"].schema.items.properties["creator"] (add "null" to type, or nullable: true in OpenAPI 3.0).

## Other body findings (15)

Undocumented fields and loose constraints on successful responses. Documentation gaps, not violations.

- `response-undocumented-property` (body, info) at `GET /orgs/{org}/activities/feeds > response 200 > application/json > /0/act_user/username`
  - response body at /0/act_user/username: property "username" is not documented (and 9 more like it)
  - Request: `GET /orgs/gitea/activities/feeds -> 200 application/json;charset=utf-8`
  - Actual: `"username"`
  - If the spec is the source of truth: Stop returning "username" from GET /orgs/{org}/activities/feeds if it is not part of the contract.
  - If the implementation is the source of truth: Add "username" to paths["/orgs/{org}/activities/feeds"].get.responses["200"].content["application/json"].schema.items.properties["act_user"].properties.
- `response-constraint-violation` (body, warning) at `GET /orgs/{org}/activities/feeds > response 200 > application/json > /0/repo/owner/email`
  - response body at /0/repo/owner/email: value does not match format "email" (and 9 more like it)
  - Request: `GET /orgs/gitea/activities/feeds -> 200 application/json;charset=utf-8`
  - Expected: `"email"`
  - Actual: `""`
  - If the spec is the source of truth: Make response body at /0/repo/owner/email satisfy format "email".
  - If the implementation is the source of truth: Relax format at paths["/orgs/{org}/activities/feeds"].get.responses["200"].content["application/json"].schema.items.properties["repo"].properties["owner"].properties["email"] to cover what is returned.
- `response-undocumented-property` (body, info) at `GET /orgs/{org}/activities/feeds > response 200 > application/json > /0/repo/owner/username`
  - response body at /0/repo/owner/username: property "username" is not documented (and 9 more like it)
  - Request: `GET /orgs/gitea/activities/feeds -> 200 application/json;charset=utf-8`
  - Actual: `"username"`
  - If the spec is the source of truth: Stop returning "username" from GET /orgs/{org}/activities/feeds if it is not part of the contract.
  - If the implementation is the source of truth: Add "username" to paths["/orgs/{org}/activities/feeds"].get.responses["200"].content["application/json"].schema.items.properties["repo"].properties["owner"].properties.
- `response-undocumented-property` (body, info) at `GET /orgs/{org}/public_members > response 200 > application/json > /0/username`
  - response body at /0/username: property "username" is not documented (and 9 more like it)
  - Request: `GET /orgs/gitea/public_members -> 200 application/json;charset=utf-8`
  - Actual: `"username"`
  - If the spec is the source of truth: Stop returning "username" from GET /orgs/{org}/public_members if it is not part of the contract.
  - If the implementation is the source of truth: Add "username" to paths["/orgs/{org}/public_members"].get.responses["200"].content["application/json"].schema.items.properties.
- `response-constraint-violation` (body, warning) at `GET /orgs/{org}/repos > response 200 > application/json > /0/owner/email`
  - response body at /0/owner/email: value does not match format "email" (and 9 more like it)
  - Request: `GET /orgs/gitea/repos -> 200 application/json;charset=utf-8`
  - Expected: `"email"`
  - Actual: `""`
  - If the spec is the source of truth: Make response body at /0/owner/email satisfy format "email".
  - If the implementation is the source of truth: Relax format at paths["/orgs/{org}/repos"].get.responses["200"].content["application/json"].schema.items.properties["owner"].properties["email"] to cover what is returned.
- `response-undocumented-property` (body, info) at `GET /orgs/{org}/repos > response 200 > application/json > /0/owner/username`
  - response body at /0/owner/username: property "username" is not documented (and 9 more like it)
  - Request: `GET /orgs/gitea/repos -> 200 application/json;charset=utf-8`
  - Actual: `"username"`
  - If the spec is the source of truth: Stop returning "username" from GET /orgs/{org}/repos if it is not part of the contract.
  - If the implementation is the source of truth: Add "username" to paths["/orgs/{org}/repos"].get.responses["200"].content["application/json"].schema.items.properties["owner"].properties.
- `response-constraint-violation` (body, warning) at `GET /repos/{owner}/{repo} > response 200 > application/json > /owner/email`
  - response body at /owner/email: value does not match format "email"
  - Request: `GET /repos/gitea/tea -> 200 application/json;charset=utf-8`
  - Expected: `"email"`
  - Actual: `""`
  - If the spec is the source of truth: Make response body at /owner/email satisfy format "email".
  - If the implementation is the source of truth: Relax format at paths["/repos/{owner}/{repo}"].get.responses["200"].content["application/json"].schema.properties["owner"].properties["email"] to cover what is returned.
- `response-undocumented-property` (body, info) at `GET /repos/{owner}/{repo} > response 200 > application/json > /owner/username`
  - response body at /owner/username: property "username" is not documented
  - Request: `GET /repos/gitea/tea -> 200 application/json;charset=utf-8`
  - Actual: `"username"`
  - If the spec is the source of truth: Stop returning "username" from GET /repos/{owner}/{repo} if it is not part of the contract.
  - If the implementation is the source of truth: Add "username" to paths["/repos/{owner}/{repo}"].get.responses["200"].content["application/json"].schema.properties["owner"].properties.
- `response-undocumented-property` (body, info) at `GET /repos/{owner}/{repo}/activities/feeds > response 200 > application/json > /0/act_user/username`
  - response body at /0/act_user/username: property "username" is not documented (and 9 more like it)
  - Request: `GET /repos/gitea/tea/activities/feeds -> 200 application/json;charset=utf-8`
  - Actual: `"username"`
  - If the spec is the source of truth: Stop returning "username" from GET /repos/{owner}/{repo}/activities/feeds if it is not part of the contract.
  - If the implementation is the source of truth: Add "username" to paths["/repos/{owner}/{repo}/activities/feeds"].get.responses["200"].content["application/json"].schema.items.properties["act_user"].properties.
- `response-constraint-violation` (body, warning) at `GET /repos/{owner}/{repo}/activities/feeds > response 200 > application/json > /0/repo/owner/email`
  - response body at /0/repo/owner/email: value does not match format "email" (and 9 more like it)
  - Request: `GET /repos/gitea/tea/activities/feeds -> 200 application/json;charset=utf-8`
  - Expected: `"email"`
  - Actual: `""`
  - If the spec is the source of truth: Make response body at /0/repo/owner/email satisfy format "email".
  - If the implementation is the source of truth: Relax format at paths["/repos/{owner}/{repo}/activities/feeds"].get.responses["200"].content["application/json"].schema.items.properties["repo"].properties["owner"].properties["email"] to cover what is returned.
- `response-undocumented-property` (body, info) at `GET /repos/{owner}/{repo}/activities/feeds > response 200 > application/json > /0/repo/owner/username`
  - response body at /0/repo/owner/username: property "username" is not documented (and 9 more like it)
  - Request: `GET /repos/gitea/tea/activities/feeds -> 200 application/json;charset=utf-8`
  - Actual: `"username"`
  - If the spec is the source of truth: Stop returning "username" from GET /repos/{owner}/{repo}/activities/feeds if it is not part of the contract.
  - If the implementation is the source of truth: Add "username" to paths["/repos/{owner}/{repo}/activities/feeds"].get.responses["200"].content["application/json"].schema.items.properties["repo"].properties["owner"].properties.
- `response-undocumented-property` (body, info) at `GET /repos/{owner}/{repo}/commits > response 200 > application/json > /0/author/username`
  - response body at /0/author/username: property "username" is not documented (and 9 more like it)
  - Request: `GET /repos/gitea/tea/commits -> 200 application/json;charset=utf-8`
  - Actual: `"username"`
  - If the spec is the source of truth: Stop returning "username" from GET /repos/{owner}/{repo}/commits if it is not part of the contract.
  - If the implementation is the source of truth: Add "username" to paths["/repos/{owner}/{repo}/commits"].get.responses["200"].content["application/json"].schema.items.properties["author"].properties.
- `response-undocumented-property` (body, info) at `GET /repos/{owner}/{repo}/commits > response 200 > application/json > /0/committer/username`
  - response body at /0/committer/username: property "username" is not documented (and 9 more like it)
  - Request: `GET /repos/gitea/tea/commits -> 200 application/json;charset=utf-8`
  - Actual: `"username"`
  - If the spec is the source of truth: Stop returning "username" from GET /repos/{owner}/{repo}/commits if it is not part of the contract.
  - If the implementation is the source of truth: Add "username" to paths["/repos/{owner}/{repo}/commits"].get.responses["200"].content["application/json"].schema.items.properties["committer"].properties.
- `response-constraint-violation` (body, warning) at `GET /repos/{owner}/{repo}/commits/{ref}/status > response 200 > application/json > /repository/owner/email`
  - response body at /repository/owner/email: value does not match format "email"
  - Request: `GET /repos/gitea/tea/commits/main/status -> 200 application/json;charset=utf-8`
  - Expected: `"email"`
  - Actual: `""`
  - If the spec is the source of truth: Make response body at /repository/owner/email satisfy format "email".
  - If the implementation is the source of truth: Relax format at paths["/repos/{owner}/{repo}/commits/{ref}/status"].get.responses["200"].content["application/json"].schema.properties["repository"].properties["owner"].properties["email"] to cover what is returned.
- `response-undocumented-property` (body, info) at `GET /repos/{owner}/{repo}/commits/{ref}/status > response 200 > application/json > /repository/owner/username`
  - response body at /repository/owner/username: property "username" is not documented
  - Request: `GET /repos/gitea/tea/commits/main/status -> 200 application/json;charset=utf-8`
  - Actual: `"username"`
  - If the spec is the source of truth: Stop returning "username" from GET /repos/{owner}/{repo}/commits/{ref}/status if it is not part of the contract.
  - If the implementation is the source of truth: Add "username" to paths["/repos/{owner}/{repo}/commits/{ref}/status"].get.responses["200"].content["application/json"].schema.properties["repository"].properties["owner"].properties.

## Undocumented error responses (14)

3xx and 4xx statuses the spec does not mention, usually auth or not-found cases.

- `undocumented-status` (errors, breaking) at `GET /orgs/{org}/blocks > response 401`
  - status 401 is not documented for "GET /orgs/{org}/blocks"
  - Request: `GET /orgs/gitea/blocks -> 401 application/json;charset=utf-8`
  - Expected: `["200"]`
  - Actual: `401`
  - If the spec is the source of truth: Return one of the documented statuses (200) from GET /orgs/{org}/blocks.
  - If the implementation is the source of truth: Add a "401" response under paths["/orgs/{org}/blocks"].get.responses.
- `undocumented-status` (errors, breaking) at `GET /orgs/{org}/blocks/{username} > response 401`
  - status 401 is not documented for "GET /orgs/{org}/blocks/{username}"
  - Request: `GET /orgs/gitea/blocks/gitea -> 401 application/json;charset=utf-8`
  - Expected: `["204","404"]`
  - Actual: `401`
  - If the spec is the source of truth: Return one of the documented statuses (204, 404) from GET /orgs/{org}/blocks/{username}.
  - If the implementation is the source of truth: Add a "401" response under paths["/orgs/{org}/blocks/{username}"].get.responses.
- `undocumented-status` (errors, breaking) at `GET /orgs/{org}/labels/{id} > response 401`
  - status 401 is not documented for "GET /orgs/{org}/labels/{id}"
  - Request: `GET /orgs/gitea/labels/1 -> 401 application/json;charset=utf-8`
  - Expected: `["200","404"]`
  - Actual: `401`
  - If the spec is the source of truth: Return one of the documented statuses (200, 404) from GET /orgs/{org}/labels/{id}.
  - If the implementation is the source of truth: Add a "401" response under paths["/orgs/{org}/labels/{id}"].get.responses.
- `undocumented-status` (errors, breaking) at `GET /packages/{owner} > response 401`
  - status 401 is not documented for "GET /packages/{owner}"
  - Request: `GET /packages/gitea -> 401 application/json;charset=utf-8`
  - Expected: `["200","404"]`
  - Actual: `401`
  - If the spec is the source of truth: Return one of the documented statuses (200, 404) from GET /packages/{owner}.
  - If the implementation is the source of truth: Add a "401" response under paths["/packages/{owner}"].get.responses.
- `undocumented-status` (errors, breaking) at `GET /repos/{owner}/{repo}/actions/jobs > response 401`
  - status 401 is not documented for "GET /repos/{owner}/{repo}/actions/jobs"
  - Request: `GET /repos/gitea/tea/actions/jobs -> 401 application/json;charset=utf-8`
  - Expected: `["200","400","404","422"]`
  - Actual: `401`
  - If the spec is the source of truth: Return one of the documented statuses (200, 400, 404, 422) from GET /repos/{owner}/{repo}/actions/jobs.
  - If the implementation is the source of truth: Add a "401" response under paths["/repos/{owner}/{repo}/actions/jobs"].get.responses.
- `undocumented-status` (errors, breaking) at `GET /repos/{owner}/{repo}/actions/runners > response 401`
  - status 401 is not documented for "GET /repos/{owner}/{repo}/actions/runners"
  - Request: `GET /repos/gitea/tea/actions/runners -> 401 application/json;charset=utf-8`
  - Expected: `["200","400","404"]`
  - Actual: `401`
  - If the spec is the source of truth: Return one of the documented statuses (200, 400, 404) from GET /repos/{owner}/{repo}/actions/runners.
  - If the implementation is the source of truth: Add a "401" response under paths["/repos/{owner}/{repo}/actions/runners"].get.responses.
- `undocumented-status` (errors, breaking) at `GET /repos/{owner}/{repo}/actions/runs > response 401`
  - status 401 is not documented for "GET /repos/{owner}/{repo}/actions/runs"
  - Request: `GET /repos/gitea/tea/actions/runs -> 401 application/json;charset=utf-8`
  - Expected: `["200","400","404"]`
  - Actual: `401`
  - If the spec is the source of truth: Return one of the documented statuses (200, 400, 404) from GET /repos/{owner}/{repo}/actions/runs.
  - If the implementation is the source of truth: Add a "401" response under paths["/repos/{owner}/{repo}/actions/runs"].get.responses.
- `undocumented-status` (errors, breaking) at `GET /repos/{owner}/{repo}/actions/secrets > response 401`
  - status 401 is not documented for "GET /repos/{owner}/{repo}/actions/secrets"
  - Request: `GET /repos/gitea/tea/actions/secrets -> 401 application/json;charset=utf-8`
  - Expected: `["200","404"]`
  - Actual: `401`
  - If the spec is the source of truth: Return one of the documented statuses (200, 404) from GET /repos/{owner}/{repo}/actions/secrets.
  - If the implementation is the source of truth: Add a "401" response under paths["/repos/{owner}/{repo}/actions/secrets"].get.responses.
- `undocumented-status` (errors, breaking) at `GET /repos/{owner}/{repo}/actions/variables > response 401`
  - status 401 is not documented for "GET /repos/{owner}/{repo}/actions/variables"
  - Request: `GET /repos/gitea/tea/actions/variables -> 401 application/json;charset=utf-8`
  - Expected: `["200","400","404"]`
  - Actual: `401`
  - If the spec is the source of truth: Return one of the documented statuses (200, 400, 404) from GET /repos/{owner}/{repo}/actions/variables.
  - If the implementation is the source of truth: Add a "401" response under paths["/repos/{owner}/{repo}/actions/variables"].get.responses.
- `undocumented-status` (errors, breaking) at `GET /repos/{owner}/{repo}/actions/workflows > response 401`
  - status 401 is not documented for "GET /repos/{owner}/{repo}/actions/workflows"
  - Request: `GET /repos/gitea/tea/actions/workflows -> 401 application/json;charset=utf-8`
  - Expected: `["200","400","403","404","422","500"]`
  - Actual: `401`
  - If the spec is the source of truth: Return one of the documented statuses (200, 400, 403, 404, 422, 500) from GET /repos/{owner}/{repo}/actions/workflows.
  - If the implementation is the source of truth: Add a "401" response under paths["/repos/{owner}/{repo}/actions/workflows"].get.responses.
- `undocumented-status` (errors, breaking) at `GET /repos/{owner}/{repo}/assignees > response 401`
  - status 401 is not documented for "GET /repos/{owner}/{repo}/assignees"
  - Request: `GET /repos/gitea/tea/assignees -> 401 application/json;charset=utf-8`
  - Expected: `["200","404"]`
  - Actual: `401`
  - If the spec is the source of truth: Return one of the documented statuses (200, 404) from GET /repos/{owner}/{repo}/assignees.
  - If the implementation is the source of truth: Add a "401" response under paths["/repos/{owner}/{repo}/assignees"].get.responses.
- `undocumented-status` (errors, breaking) at `GET /repos/{owner}/{repo}/branch_protections > response 401`
  - status 401 is not documented for "GET /repos/{owner}/{repo}/branch_protections"
  - Request: `GET /repos/gitea/tea/branch_protections -> 401 application/json;charset=utf-8`
  - Expected: `["200"]`
  - Actual: `401`
  - If the spec is the source of truth: Return one of the documented statuses (200) from GET /repos/{owner}/{repo}/branch_protections.
  - If the implementation is the source of truth: Add a "401" response under paths["/repos/{owner}/{repo}/branch_protections"].get.responses.
- `undocumented-status` (errors, breaking) at `GET /repos/{owner}/{repo}/branch_protections/{name} > response 401`
  - status 401 is not documented for "GET /repos/{owner}/{repo}/branch_protections/{name}"
  - Request: `GET /repos/gitea/tea/branch_protections/gitea -> 401 application/json;charset=utf-8`
  - Expected: `["200","404"]`
  - Actual: `401`
  - If the spec is the source of truth: Return one of the documented statuses (200, 404) from GET /repos/{owner}/{repo}/branch_protections/{name}.
  - If the implementation is the source of truth: Add a "401" response under paths["/repos/{owner}/{repo}/branch_protections/{name}"].get.responses.
- `undocumented-status` (errors, breaking) at `GET /repos/{owner}/{repo}/collaborators > response 401`
  - status 401 is not documented for "GET /repos/{owner}/{repo}/collaborators"
  - Request: `GET /repos/gitea/tea/collaborators -> 401 application/json;charset=utf-8`
  - Expected: `["200","404"]`
  - Actual: `401`
  - If the spec is the source of truth: Return one of the documented statuses (200, 404) from GET /repos/{owner}/{repo}/collaborators.
  - If the implementation is the source of truth: Add a "401" response under paths["/repos/{owner}/{repo}/collaborators"].get.responses.

## Reproduce

```sh
curl -s -H 'Accept: application/json' 'https://gitea.com/api/v1/orgs/gitea/activities/feeds'
```

## Data

- Findings: https://github.com/apidrifter/apidrifter/tree/main/tools/survey/results/gitea.findings.json
- Requests sent: https://github.com/apidrifter/apidrifter/tree/main/tools/survey/results/gitea.observations.json
- Tool: https://apidrifter.com/docs/cli/ (reproduce with apidrifter run; target definition in tools/survey/targets.json)
