Summary
The details field on the error schemas is documented by example as a play.numscript.org link. No code path in this repository ever puts a URL there — the only writer passes err.Error(), plain text. The example appears to be a Numary-era leftover, and it actively misleads clients into treating the field as a link.
Evidence
The example, on a bare type: string field with no format and no description:
openapi/v1.yaml:1515 and :1865
openapi/v2.yaml:2855
openapi/v3.yaml:2256
https://play.numscript.org/?payload=eyJlcnJvciI6ImFjY291bnQgaGFkIGluc3VmZmljaWVudCBmdW5kcyJ9
What actually populates the field — the sole writer is BadRequestWithDetails (go-libs/v5/pkg/transport/api/utils.go:65), and every ledger caller passes err.Error():
internal/api/v1/controllers_accounts_add_metadata.go:23
internal/api/v1/controllers_accounts_delete_metadata.go:18
internal/api/v1/controllers_accounts_read.go:24
internal/api/v2/controllers_accounts_add_metadata.go:21
internal/api/v2/controllers_accounts_delete_metadata.go:18
internal/api/v2/controllers_accounts_read.go:22
So details carries a validation error string on those account endpoints, and is absent elsewhere (json:"details,omitempty", go-libs/v5/pkg/transport/api/response.go:24).
grep -rn 'play.numscript' over the Go sources returns nothing. Nothing constructs a playground link.
A second, sharper problem
The example implies details is populated on Numscript compilation failures. It is not. COMPILATION_FAILED is raised via plain api.BadRequest, which never sets the field:
internal/api/v2/controllers_transactions_create.go:56 — api.BadRequest(w, common.ErrCompilationFailed, err)
internal/api/v1/controllers_transactions_create.go:94
The compiler diagnostics are in errorMessage. So on the one error where a reader would most expect details, it is omitted entirely.
Why this matters
Beyond being wrong, the example invites a specific bad implementation. A field whose documented example is a URL gets rendered as a clickable link — but its real contents are err.Error(), which is influenced by request input (account addresses, metadata keys). Encouraging clients to treat that as a URL to render is a small injection footgun for anyone surfacing API errors in a UI.
Suggested fix
- Replace the example with something representative of the real contents, e.g.
invalid account address: user:john: — or drop the example rather than substitute another guess.
- Add a short description: optional, human-readable detail on certain validation errors, opaque, not structured, not a URL, absent on most errors including
COMPILATION_FAILED.
- Same treatment across
v1.yaml, v2.yaml and v3.yaml.
Worth deciding separately whether COMPILATION_FAILED should populate details with the diagnostics — that would be a genuine improvement, but it is a behaviour change and not what this issue asks for.
Context
Found while correcting the API errors reference page in formancehq/docs#168, which had documented details as carrying Numscript diagnostics on COMPILATION_FAILED. A review bot then flagged that page and proposed documenting the field as a diagnostic URL, citing this example — which is how the stale example came to light: it is already causing people to draw the wrong conclusion. The docs page now describes the field accurately and notes the example is stale, so nothing is blocked on this.
Summary
The
detailsfield on the error schemas is documented by example as aplay.numscript.orglink. No code path in this repository ever puts a URL there — the only writer passeserr.Error(), plain text. The example appears to be a Numary-era leftover, and it actively misleads clients into treating the field as a link.Evidence
The example, on a bare
type: stringfield with noformatand no description:openapi/v1.yaml:1515and:1865openapi/v2.yaml:2855openapi/v3.yaml:2256What actually populates the field — the sole writer is
BadRequestWithDetails(go-libs/v5/pkg/transport/api/utils.go:65), and every ledger caller passeserr.Error():internal/api/v1/controllers_accounts_add_metadata.go:23internal/api/v1/controllers_accounts_delete_metadata.go:18internal/api/v1/controllers_accounts_read.go:24internal/api/v2/controllers_accounts_add_metadata.go:21internal/api/v2/controllers_accounts_delete_metadata.go:18internal/api/v2/controllers_accounts_read.go:22So
detailscarries a validation error string on those account endpoints, and is absent elsewhere (json:"details,omitempty",go-libs/v5/pkg/transport/api/response.go:24).grep -rn 'play.numscript'over the Go sources returns nothing. Nothing constructs a playground link.A second, sharper problem
The example implies
detailsis populated on Numscript compilation failures. It is not.COMPILATION_FAILEDis raised via plainapi.BadRequest, which never sets the field:internal/api/v2/controllers_transactions_create.go:56—api.BadRequest(w, common.ErrCompilationFailed, err)internal/api/v1/controllers_transactions_create.go:94The compiler diagnostics are in
errorMessage. So on the one error where a reader would most expectdetails, it is omitted entirely.Why this matters
Beyond being wrong, the example invites a specific bad implementation. A field whose documented example is a URL gets rendered as a clickable link — but its real contents are
err.Error(), which is influenced by request input (account addresses, metadata keys). Encouraging clients to treat that as a URL to render is a small injection footgun for anyone surfacing API errors in a UI.Suggested fix
invalid account address: user:john:— or drop the example rather than substitute another guess.COMPILATION_FAILED.v1.yaml,v2.yamlandv3.yaml.Worth deciding separately whether
COMPILATION_FAILEDshould populatedetailswith the diagnostics — that would be a genuine improvement, but it is a behaviour change and not what this issue asks for.Context
Found while correcting the API errors reference page in formancehq/docs#168, which had documented
detailsas carrying Numscript diagnostics onCOMPILATION_FAILED. A review bot then flagged that page and proposed documenting the field as a diagnostic URL, citing this example — which is how the stale example came to light: it is already causing people to draw the wrong conclusion. The docs page now describes the field accurately and notes the example is stale, so nothing is blocked on this.