MCPcopy Create free account
hub / github.com/PerpetualSoftware/pad / writeInternalError

Function writeInternalError

internal/server/server.go:2249–2306  ·  view source on GitHub ↗

writeInternalError logs the real error server-side and sends a generic message to the client. This prevents leaking SQL errors, file paths, and other internal details.

(w http.ResponseWriter, err error)

Source from the content-addressed store, hash-verified

2247// message to the client. This prevents leaking SQL errors, file paths,
2248// and other internal details.
2249func writeInternalError(w http.ResponseWriter, err error) {
2250 // The store's NUL refusal is a DECISION, not a fault, and it is mapped
2251 // here rather than at each handler for the same reason Layer A lives at
2252 // the driver: this is the one funnel every 500 already passes through, so
2253 // mapping it once covers every handler that exists and every one that will
2254 // (DOC-2823 S1). Enumerating error blocks is what the item-title unit had
2255 // to do three times in one function before a structural test caught the
2256 // third.
2257 //
2258 // 400, matching what the HTTP gate answers for the SAME value refused at
2259 // the door. Two statuses for one rule would be the layers disagreeing
2260 // again, in the response this time instead of in the predicate.
2261 //
2262 // The honest residual: a value can reach the store from something the
2263 // SERVER composed rather than the caller supplied — that is BUG-2814's
2264 // re-emit population — and for those a 400 tells the caller their request
2265 // was bad when it was our stored data. It is still the better answer than
2266 // 500, because the request is understood and will be refused identically
2267 // on retry, and the log line below keeps the detail. If the re-emit case
2268 // ever needs its own status, it needs its own error type first.
2269 if reason, ok := nulRefusalReason(err); ok {
2270 slog.Warn("write refused: invalid text parameter", "error", err)
2271 writeError(w, http.StatusBadRequest, "bad_request", reason)
2272 return
2273 }
2274 // The outbox row cap is likewise a decision, not a fault, and is mapped in
2275 // the same funnel for the same reason (BUG-2827). 413 with a *_too_large
2276 // code follows the house precedent set by rename_cascade_too_large rather
2277 // than inventing a second spelling for "this operation produces more than
2278 // the server will process in one go".
2279 //
2280 // The literal reading of 413 is that the REQUEST entity is too large, and
2281 // here the request is small while the event it derives is not. Taken
2282 // alone that argues for 422. It loses to consistency: an operator watching
2283 // for cascade refusals should not have to know which of two size bounds
2284 // fired to know which status to grep for, and the message says plainly
2285 // what was actually too big.
2286 //
2287 // Composed from the TYPED fields, never by splicing err.Error(), so no
2288 // wrapper the call path added is published to the caller.
2289 var oversized *store.OversizedOutboxPayloadError
2290 if errors.As(err, &oversized) {
2291 slog.Warn("write refused: outbox payload over the size limit",
2292 "event_type", oversized.EventType, "bytes", oversized.Bytes, "limit", oversized.Limit)
2293 // The message names WHAT was measured, because the store refuses on two
2294 // different measurements — the member content before marshalling, and
2295 // the row as stored — and a caller told only "%d bytes" for both
2296 // cannot reconcile two different numbers for one mutation (codex
2297 // round 3).
2298 writeError(w, http.StatusRequestEntityTooLarge, "event_payload_too_large",
2299 fmt.Sprintf("This change would record a %s event larger than the server will store in one "+
2300 "row: %s is %d bytes, and the limit is %d. Split the change into smaller ones and try again.",
2301 oversized.EventType, oversized.Measured, oversized.Bytes, oversized.Limit))
2302 return
2303 }
2304 slog.Error("internal server error", "error", err)
2305 writeError(w, http.StatusInternalServerError, "internal_error", "An internal error occurred")
2306}

Calls 3

nulRefusalReasonFunction · 0.85
writeErrorFunction · 0.85
ErrorMethod · 0.45