ux(api): endpoint without a leading slash becomes /api/v1repos/... and surfaces a bare server 404 - normalize like gh instead of puzzling the user #198

Closed
opened 2026-07-17 14:30:53 +00:00 by hexajon · 0 comments
hexajon commented 2026-07-17 14:30:53 +00:00 (Migrated from codeberg.org)

Repro

madtea api "repos/sixfold_space/madtea"
# -> Error: API error 404: Not found.
madtea api "/repos/sixfold_space/madtea"
# -> works

Root cause

internal/gitea/client_http.go:66 joins with plain concatenation: c.baseURL + "/api/v1" + endpoint. A slashless endpoint produces https://<forge>/api/v1repos/..., the forge routes it nowhere, and the user gets a bare server 404 that is indistinguishable from "repo does not exist", "wrong forge", or "bad token". Hit live while diagnosing #197: three consecutive endpoints (repo GET, org repos list, user repos list) all 404ed identically and the missing slash was only found by reading the client source. The help text does say "The endpoint should start with /", but a doc line is not a guardrail - the command happily sends the malformed URL.

Expected

Normalize, do not lecture: prepend the missing "/" before the join. That is gh parity (ADR 0016 - gh's own canonical examples are slashless: gh api repos/{owner}/{repo}/releases), it can never break an existing correct call, and the puzzle class disappears entirely. Applies to both the CLI madtea api and madt_api_call (same client join). The --raw path should get the same treatment.

If normalization is rejected for some reason, the fallback is a client-side refusal BEFORE any HTTP call: endpoint must start with "/" - got "repos/..."; did you mean "/repos/..."? - but normalize is strictly better.

  • #105 (closed) made api exit nonzero on HTTP errors; this is the next rung - don't manufacture the HTTP error in the first place.
  • #197 - the debugging session this bit.
## Repro ``` madtea api "repos/sixfold_space/madtea" # -> Error: API error 404: Not found. madtea api "/repos/sixfold_space/madtea" # -> works ``` ## Root cause `internal/gitea/client_http.go:66` joins with plain concatenation: `c.baseURL + "/api/v1" + endpoint`. A slashless endpoint produces `https://<forge>/api/v1repos/...`, the forge routes it nowhere, and the user gets a bare server 404 that is indistinguishable from "repo does not exist", "wrong forge", or "bad token". Hit live while diagnosing #197: three consecutive endpoints (repo GET, org repos list, user repos list) all 404ed identically and the missing slash was only found by reading the client source. The help text does say "The endpoint should start with /", but a doc line is not a guardrail - the command happily sends the malformed URL. ## Expected Normalize, do not lecture: prepend the missing "/" before the join. That is gh parity (ADR 0016 - gh's own canonical examples are slashless: `gh api repos/{owner}/{repo}/releases`), it can never break an existing correct call, and the puzzle class disappears entirely. Applies to both the CLI `madtea api` and `madt_api_call` (same client join). The --raw path should get the same treatment. If normalization is rejected for some reason, the fallback is a client-side refusal BEFORE any HTTP call: `endpoint must start with "/" - got "repos/..."; did you mean "/repos/..."?` - but normalize is strictly better. ## Related - #105 (closed) made api exit nonzero on HTTP errors; this is the next rung - don't manufacture the HTTP error in the first place. - #197 - the debugging session this bit.
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
sixfold-space/madtea#198
No description provided.