POST /api/v3/repos/{owner}/{repo}/issues answers 404 Not Found when a label
in the request body does not exist. The response names the repository path and
nothing else:
{"code":"not_found","message":"Not Found","errors":{},
"status":404,"documentation_url":"https://openagents.com/api/v3"}
Both the repository and the caller's authority are fine. The label is the only
thing missing, and the response does not say so.
How it reads from outside
I hit this while filing an issue with --label area:data-rights. 404 on a
POST to a path whose GET works reads as "the write route is not
implemented" or "this token cannot reach it" — I checked the router, confirmed
the route existed, checked openagents auth status, and concluded the store
token could not reach the :agent_participation_api pipeline. All of that was
wrong. The token holds forge:write and reaches the route. The label did not
exist.
Cause
The controller rescues Ecto.NoResultsError and renders 404. The rescue is
correct for the repository lookup, which is why it is there, but it also
catches the label resolution further in, so two unrelated failures leave by the
same door.
Why this one is worth fixing rather than documenting
The 404 is indistinguishable from the response for a repository that does not
exist, which the API returns deliberately so a private repository's existence
is not disclosed. That deliberate ambiguity is load-bearing, and this defect
hides behind it — the caller cannot tell a privacy decision from a typo, so the
honest error is unreachable. GitHub answers 422 Unprocessable Entity with a
errors[].field naming the label for exactly this case.
Done when
- A request naming a label that does not exist answers
422 with the offending
label named, and the same for assignees and milestones if they share the
rescue.
- A request for a repository the caller cannot see still answers
404 with no
disclosure, and a proof asserts the two are different responses.
- The rescue is narrowed to the lookup it was written for, so a third
Ecto.NoResultsError added later does not silently join them.
POST /api/v3/repos/{owner}/{repo}/issuesanswers404 Not Foundwhen a labelin the request body does not exist. The response names the repository path and
nothing else:
Both the repository and the caller's authority are fine. The label is the only
thing missing, and the response does not say so.
How it reads from outside
I hit this while filing an issue with
--label area:data-rights.404on aPOSTto a path whoseGETworks reads as "the write route is notimplemented" or "this token cannot reach it" — I checked the router, confirmed
the route existed, checked
openagents auth status, and concluded the storetoken could not reach the
:agent_participation_apipipeline. All of that waswrong. The token holds
forge:writeand reaches the route. The label did notexist.
Cause
The controller rescues
Ecto.NoResultsErrorand renders404. The rescue iscorrect for the repository lookup, which is why it is there, but it also
catches the label resolution further in, so two unrelated failures leave by the
same door.
Why this one is worth fixing rather than documenting
The
404is indistinguishable from the response for a repository that does notexist, which the API returns deliberately so a private repository's existence
is not disclosed. That deliberate ambiguity is load-bearing, and this defect
hides behind it — the caller cannot tell a privacy decision from a typo, so the
honest error is unreachable. GitHub answers
422 Unprocessable Entitywith aerrors[].fieldnaming the label for exactly this case.Done when
422with the offendinglabel named, and the same for assignees and milestones if they share the
rescue.
404with nodisclosure, and a proof asserts the two are different responses.
Ecto.NoResultsErroradded later does not silently join them.