[{"data":1,"prerenderedAt":1720},["ShallowReactive",2],{"navigation_docs_en":3,"-en-http-error-responses":342,"-en-http-error-responses-surround":1715},[4,45,61,96,132,166,196,217,241,265],{"title":5,"icon":6,"path":7,"stem":8,"children":9,"page":44},"Getting Started","i-lucide-rocket","\u002Fen\u002Fgetting-started","en\u002F1.getting-started",[10,15,20,24,29,34,39],{"title":11,"path":12,"stem":13,"icon":14},"Introduction","\u002Fen\u002Fgetting-started\u002Fintroduction","en\u002F1.getting-started\u002F1.introduction","i-lucide-house",{"title":16,"path":17,"stem":18,"icon":19},"Coming from Laravel","\u002Fen\u002Fgetting-started\u002Fcoming-from-laravel","en\u002F1.getting-started\u002F2.coming-from-laravel","i-lucide-arrow-right-left",{"title":21,"path":22,"stem":23,"icon":19},"Coming from Symfony","\u002Fen\u002Fgetting-started\u002Fcoming-from-symfony","en\u002F1.getting-started\u002F3.coming-from-symfony",{"title":25,"path":26,"stem":27,"icon":28},"Installation","\u002Fen\u002Fgetting-started\u002Finstallation","en\u002F1.getting-started\u002F4.installation","i-lucide-download",{"title":30,"path":31,"stem":32,"icon":33},"Your first module","\u002Fen\u002Fgetting-started\u002Ffirst-module","en\u002F1.getting-started\u002F5.first-module","i-lucide-package-plus",{"title":35,"path":36,"stem":37,"icon":38},"Project structure","\u002Fen\u002Fgetting-started\u002Fproject-structure","en\u002F1.getting-started\u002F6.project-structure","i-lucide-folder-tree",{"title":40,"path":41,"stem":42,"icon":43},"The shop sample application","\u002Fen\u002Fgetting-started\u002Fsample-app","en\u002F1.getting-started\u002F7.sample-app","i-lucide-shopping-cart",false,{"title":46,"icon":47,"path":48,"stem":49,"children":50,"page":44},"Reference","i-lucide-book-open","\u002Fen\u002Freference","en\u002F10.reference",[51,56],{"title":52,"path":53,"stem":54,"icon":55},"Configuration","\u002Fen\u002Freference\u002Fconfiguration","en\u002F10.reference\u002F1.configuration","i-lucide-settings",{"title":57,"path":58,"stem":59,"icon":60},"External dependencies","\u002Fen\u002Freference\u002Fdependencies","en\u002F10.reference\u002F2.dependencies","i-lucide-package",{"title":62,"icon":63,"path":64,"stem":65,"children":66,"page":44},"Concepts","i-lucide-lightbulb","\u002Fen\u002Fconcepts","en\u002F2.concepts",[67,72,77,82,86,91],{"title":68,"path":69,"stem":70,"icon":71},"Architecture","\u002Fen\u002Fconcepts\u002Farchitecture","en\u002F2.concepts\u002F1.architecture","i-lucide-layers",{"title":73,"path":74,"stem":75,"icon":76},"Application lifecycle","\u002Fen\u002Fconcepts\u002Fapplication-lifecycle","en\u002F2.concepts\u002F2.application-lifecycle","i-lucide-power",{"title":78,"path":79,"stem":80,"icon":81},"Error model","\u002Fen\u002Fconcepts\u002Ferror-model","en\u002F2.concepts\u002F3.error-model","i-lucide-shield-alert",{"title":52,"path":83,"stem":84,"icon":85},"\u002Fen\u002Fconcepts\u002Fconfiguration","en\u002F2.concepts\u002F4.configuration","i-lucide-settings-2",{"title":87,"path":88,"stem":89,"icon":90},"Codegen pipeline","\u002Fen\u002Fconcepts\u002Fcodegen-pipeline","en\u002F2.concepts\u002F5.codegen-pipeline","i-lucide-file-json",{"title":92,"path":93,"stem":94,"icon":95},"Design patterns","\u002Fen\u002Fconcepts\u002Fdesign-patterns","en\u002F2.concepts\u002F6.design-patterns","i-lucide-puzzle",{"title":97,"icon":98,"path":99,"stem":100,"children":101,"page":44},"HTTP & Routing","i-lucide-globe","\u002Fen\u002Fhttp","en\u002F3.http",[102,107,112,117,122,127],{"title":103,"path":104,"stem":105,"icon":106},"The server core","\u002Fen\u002Fhttp\u002Fserver","en\u002F3.http\u002F1.server","i-lucide-server",{"title":108,"path":109,"stem":110,"icon":111},"The Fiber engine","\u002Fen\u002Fhttp\u002Ffiber","en\u002F3.http\u002F2.fiber","i-lucide-zap",{"title":113,"path":114,"stem":115,"icon":116},"The chi engine","\u002Fen\u002Fhttp\u002Fchi","en\u002F3.http\u002F3.chi","i-lucide-route",{"title":118,"path":119,"stem":120,"icon":121},"Error responses","\u002Fen\u002Fhttp\u002Ferror-responses","en\u002F3.http\u002F4.error-responses","i-lucide-octagon-alert",{"title":123,"path":124,"stem":125,"icon":126},"Validation","\u002Fen\u002Fhttp\u002Fvalidation","en\u002F3.http\u002F5.validation","i-lucide-badge-check",{"title":128,"path":129,"stem":130,"icon":131},"Pagination","\u002Fen\u002Fhttp\u002Fpagination","en\u002F3.http\u002F6.pagination","i-lucide-list-ordered",{"title":133,"icon":134,"path":135,"stem":136,"children":137,"page":44},"Database","i-lucide-database","\u002Fen\u002Fdatabase","en\u002F4.database",[138,142,147,151,156,161],{"title":139,"path":140,"stem":141,"icon":134},"Overview","\u002Fen\u002Fdatabase\u002Foverview","en\u002F4.database\u002F1.overview",{"title":143,"path":144,"stem":145,"icon":146},"pgx","\u002Fen\u002Fdatabase\u002Fpgx","en\u002F4.database\u002F2.pgx","i-lucide-plug",{"title":148,"path":149,"stem":150,"icon":71},"bun","\u002Fen\u002Fdatabase\u002Fbun","en\u002F4.database\u002F3.bun",{"title":152,"path":153,"stem":154,"icon":155},"Transactions","\u002Fen\u002Fdatabase\u002Ftransactions","en\u002F4.database\u002F4.transactions","i-lucide-git-merge",{"title":157,"path":158,"stem":159,"icon":160},"Migrations","\u002Fen\u002Fdatabase\u002Fmigrations","en\u002F4.database\u002F5.migrations","i-lucide-file-stack",{"title":162,"path":163,"stem":164,"icon":165},"Seeders","\u002Fen\u002Fdatabase\u002Fseeding","en\u002F4.database\u002F6.seeding","i-lucide-sprout",{"title":167,"icon":168,"path":169,"stem":170,"children":171,"page":44},"Async & Background","i-lucide-workflow","\u002Fen\u002Fasync","en\u002F5.async",[172,176,181,186,191],{"title":173,"path":174,"stem":175,"icon":131},"Queue","\u002Fen\u002Fasync\u002Fqueue","en\u002F5.async\u002F1.queue",{"title":177,"path":178,"stem":179,"icon":180},"Events","\u002Fen\u002Fasync\u002Fevents","en\u002F5.async\u002F2.events","i-lucide-radio",{"title":182,"path":183,"stem":184,"icon":185},"Outbox","\u002Fen\u002Fasync\u002Foutbox","en\u002F5.async\u002F3.outbox","i-lucide-inbox",{"title":187,"path":188,"stem":189,"icon":190},"Scheduling","\u002Fen\u002Fasync\u002Fscheduler","en\u002F5.async\u002F4.scheduler","i-lucide-calendar-clock",{"title":192,"path":193,"stem":194,"icon":195},"Worker","\u002Fen\u002Fasync\u002Fworker","en\u002F5.async\u002F5.worker","i-lucide-cog",{"title":197,"icon":198,"path":199,"stem":200,"children":201,"page":44},"Security","i-lucide-shield-check","\u002Fen\u002Fsecurity","en\u002F6.security",[202,207,212],{"title":203,"path":204,"stem":205,"icon":206},"Authentication","\u002Fen\u002Fsecurity\u002Fauthentication","en\u002F6.security\u002F1.authentication","i-lucide-key-round",{"title":208,"path":209,"stem":210,"icon":211},"RBAC","\u002Fen\u002Fsecurity\u002Frbac","en\u002F6.security\u002F2.rbac","i-lucide-users",{"title":213,"path":214,"stem":215,"icon":216},"Policies","\u002Fen\u002Fsecurity\u002Fpolicies","en\u002F6.security\u002F3.policies","i-lucide-gavel",{"title":218,"icon":219,"path":220,"stem":221,"children":222,"page":44},"Observability","i-lucide-activity","\u002Fen\u002Fobservability","en\u002F7.observability",[223,226,231,236],{"title":139,"path":224,"stem":225,"icon":219},"\u002Fen\u002Fobservability\u002Foverview","en\u002F7.observability\u002F1.overview",{"title":227,"path":228,"stem":229,"icon":230},"Logging","\u002Fen\u002Fobservability\u002Flogging","en\u002F7.observability\u002F2.logging","i-lucide-scroll-text",{"title":232,"path":233,"stem":234,"icon":235},"OpenTelemetry","\u002Fen\u002Fobservability\u002Fopentelemetry","en\u002F7.observability\u002F3.opentelemetry","i-lucide-radar",{"title":237,"path":238,"stem":239,"icon":240},"Sentry","\u002Fen\u002Fobservability\u002Fsentry","en\u002F7.observability\u002F4.sentry","i-lucide-bug",{"title":242,"icon":243,"path":244,"stem":245,"children":246,"page":44},"Storage & Mail","i-lucide-hard-drive","\u002Fen\u002Fstorage-mail","en\u002F8.storage-mail",[247,251,256,261],{"title":248,"path":249,"stem":250,"icon":243},"Storage","\u002Fen\u002Fstorage-mail\u002Fstorage","en\u002F8.storage-mail\u002F1.storage",{"title":252,"path":253,"stem":254,"icon":255},"Email","\u002Fen\u002Fstorage-mail\u002Fmail","en\u002F8.storage-mail\u002F2.mail","i-lucide-mail",{"title":257,"path":258,"stem":259,"icon":260},"Notifications","\u002Fen\u002Fstorage-mail\u002Fnotifications","en\u002F8.storage-mail\u002F3.notifications","i-lucide-bell",{"title":262,"path":263,"stem":264,"icon":180},"Realtime","\u002Fen\u002Fstorage-mail\u002Frealtime","en\u002F8.storage-mail\u002F4.realtime",{"title":266,"icon":267,"path":268,"stem":269,"children":270,"page":44},"CLI Reference","i-lucide-terminal","\u002Fen\u002Fcli","en\u002F9.cli",[271,274,279,284,289,294,299,303,308,313,318,323,328,333,337],{"title":139,"path":272,"stem":273,"icon":267},"\u002Fen\u002Fcli\u002Foverview","en\u002F9.cli\u002F1.overview",{"title":275,"path":276,"stem":277,"icon":278},"add db","\u002Fen\u002Fcli\u002Fadd-db","en\u002F9.cli\u002F10.add-db","i-lucide-database-zap",{"title":280,"path":281,"stem":282,"icon":283},"add compose \u002F add docker","\u002Fen\u002Fcli\u002Fadd-compose","en\u002F9.cli\u002F11.add-compose","i-lucide-container",{"title":285,"path":286,"stem":287,"icon":288},"add mail","\u002Fen\u002Fcli\u002Fadd-mail","en\u002F9.cli\u002F12.add-mail","i-lucide-mail-plus",{"title":290,"path":291,"stem":292,"icon":293},"add notification","\u002Fen\u002Fcli\u002Fadd-notification","en\u002F9.cli\u002F13.add-notification","i-lucide-bell-plus",{"title":295,"path":296,"stem":297,"icon":298},"add realtime","\u002Fen\u002Fcli\u002Fadd-realtime","en\u002F9.cli\u002F14.add-realtime","i-lucide-radio-tower",{"title":300,"path":301,"stem":302,"icon":165},"add seeder","\u002Fen\u002Fcli\u002Fadd-seeder","en\u002F9.cli\u002F15.add-seeder",{"title":304,"path":305,"stem":306,"icon":307},"new project","\u002Fen\u002Fcli\u002Fnew-project","en\u002F9.cli\u002F2.new-project","i-lucide-folder-plus",{"title":309,"path":310,"stem":311,"icon":312},"new module","\u002Fen\u002Fcli\u002Fnew-module","en\u002F9.cli\u002F3.new-module","i-lucide-blocks",{"title":314,"path":315,"stem":316,"icon":317},"add surface","\u002Fen\u002Fcli\u002Fadd-surface","en\u002F9.cli\u002F4.add-surface","i-lucide-layers-2",{"title":319,"path":320,"stem":321,"icon":322},"add core","\u002Fen\u002Fcli\u002Fadd-core","en\u002F9.cli\u002F5.add-core","i-lucide-box",{"title":324,"path":325,"stem":326,"icon":327},"add handler","\u002Fen\u002Fcli\u002Fadd-handler","en\u002F9.cli\u002F6.add-handler","i-lucide-webhook",{"title":329,"path":330,"stem":331,"icon":332},"new migration","\u002Fen\u002Fcli\u002Fnew-migration","en\u002F9.cli\u002F7.new-migration","i-lucide-file-plus",{"title":334,"path":335,"stem":336,"icon":195},"worker generators","\u002Fen\u002Fcli\u002Fworker-generators","en\u002F9.cli\u002F8.worker-generators",{"title":338,"path":339,"stem":340,"icon":341},"upgrade templates","\u002Fen\u002Fcli\u002Fupgrade-templates","en\u002F9.cli\u002F9.upgrade-templates","i-lucide-refresh-cw",{"id":343,"title":118,"body":344,"description":1708,"extension":1709,"links":1710,"meta":1711,"navigation":1712,"path":119,"seo":1713,"stem":120,"__hash__":1714},"docs_en\u002Fen\u002F3.http\u002F4.error-responses.md",{"type":345,"value":346,"toc":1699},"minimark",[347,381,410,415,698,729,733,854,867,880,884,891,1155,1193,1213,1217,1220,1339,1342,1397,1403,1407,1432,1562,1601,1608,1612,1636,1653,1657,1688,1695],[348,349,350,351,358,359,363,364,367,368,372,373,380],"p",{},"Every error a gpsystem service puts on the wire (a validation failure, a 404, a panic, a database timeout) is an ",[352,353,357],"a",{"href":354,"rel":355},"https:\u002F\u002Fwww.rfc-editor.org\u002Frfc\u002Frfc9457",[356],"nofollow","RFC 9457"," problem document with ",[360,361,362],"code",{},"Content-Type: application\u002Fproblem+json",". The ",[360,365,366],{},"httperr"," package guarantees that: it is the wire-facing error shape and the single place where a Go error becomes an HTTP response. ",[369,370,371],"em",{},"Building"," errors (stack, code, public message) is covered by ",[352,374,375,376,379],{"href":79},"the ",[360,377,378],{},"errs"," package and the error model","; this page covers the rendering side.",[382,383,388],"pre",{"className":384,"code":385,"language":386,"meta":387,"style":387},"language-go shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","import \"github.com\u002Fgp-system\u002Fgpsystem\u002Fhttperr\"\n","go","",[360,389,390],{"__ignoreMap":387},[391,392,395,399,403,407],"span",{"class":393,"line":394},"line",1,[391,396,398],{"class":397},"s7zQu","import",[391,400,402],{"class":401},"sMK4o"," \"",[391,404,406],{"class":405},"sBMFI","github.com\u002Fgp-system\u002Fgpsystem\u002Fhttperr",[391,408,409],{"class":401},"\"\n",[411,412,414],"h2",{"id":413},"the-problem-shape","The Problem shape",[382,416,418],{"className":384,"code":417,"language":386,"meta":387,"style":387},"type Problem struct {\n    Type     string       `json:\"type\"`\n    Title    string       `json:\"title\"`\n    Status   int          `json:\"status\"`\n    Detail   string       `json:\"detail,omitempty\"`\n    Instance string       `json:\"instance,omitempty\"`\n    Code     string       `json:\"code,omitempty\"`   \u002F\u002F machine-readable error code (extension member)\n    Errors   []FieldError `json:\"errors,omitempty\"` \u002F\u002F per-field validation errors\n\n    \u002F\u002F Dev-only debug members: only under WithExposeInternal(true), and only\n    \u002F\u002F when the error carries an errs error. Always empty in production.\n    Stack []errs.Frame `json:\"stack,omitempty\"`\n    Chain []errs.Step  `json:\"chain,omitempty\"`\n}\n\ntype FieldError struct {\n    Field   string `json:\"field\"`\n    Rule    string `json:\"rule,omitempty\"`\n    Message string `json:\"message\"`\n}\n",[360,419,420,434,455,470,487,502,517,537,560,567,573,579,602,625,631,636,648,663,678,693],{"__ignoreMap":387},[391,421,422,425,428,431],{"class":393,"line":394},[391,423,424],{"class":401},"type",[391,426,427],{"class":405}," Problem",[391,429,430],{"class":401}," struct",[391,432,433],{"class":401}," {\n",[391,435,437,441,445,448,452],{"class":393,"line":436},2,[391,438,440],{"class":439},"sTEyZ","    Type     ",[391,442,444],{"class":443},"spNyl","string",[391,446,447],{"class":401},"       `",[391,449,451],{"class":450},"sfazB","json:\"type\"",[391,453,454],{"class":401},"`\n",[391,456,458,461,463,465,468],{"class":393,"line":457},3,[391,459,460],{"class":439},"    Title    ",[391,462,444],{"class":443},[391,464,447],{"class":401},[391,466,467],{"class":450},"json:\"title\"",[391,469,454],{"class":401},[391,471,473,476,479,482,485],{"class":393,"line":472},4,[391,474,475],{"class":439},"    Status   ",[391,477,478],{"class":443},"int",[391,480,481],{"class":401},"          `",[391,483,484],{"class":450},"json:\"status\"",[391,486,454],{"class":401},[391,488,490,493,495,497,500],{"class":393,"line":489},5,[391,491,492],{"class":439},"    Detail   ",[391,494,444],{"class":443},[391,496,447],{"class":401},[391,498,499],{"class":450},"json:\"detail,omitempty\"",[391,501,454],{"class":401},[391,503,505,508,510,512,515],{"class":393,"line":504},6,[391,506,507],{"class":439},"    Instance ",[391,509,444],{"class":443},[391,511,447],{"class":401},[391,513,514],{"class":450},"json:\"instance,omitempty\"",[391,516,454],{"class":401},[391,518,520,523,525,527,530,533],{"class":393,"line":519},7,[391,521,522],{"class":439},"    Code     ",[391,524,444],{"class":443},[391,526,447],{"class":401},[391,528,529],{"class":450},"json:\"code,omitempty\"",[391,531,532],{"class":401},"`",[391,534,536],{"class":535},"sHwdD","   \u002F\u002F machine-readable error code (extension member)\n",[391,538,540,543,546,549,552,555,557],{"class":393,"line":539},8,[391,541,542],{"class":439},"    Errors   ",[391,544,545],{"class":401},"[]",[391,547,548],{"class":405},"FieldError",[391,550,551],{"class":401}," `",[391,553,554],{"class":450},"json:\"errors,omitempty\"",[391,556,532],{"class":401},[391,558,559],{"class":535}," \u002F\u002F per-field validation errors\n",[391,561,563],{"class":393,"line":562},9,[391,564,566],{"emptyLinePlaceholder":565},true,"\n",[391,568,570],{"class":393,"line":569},10,[391,571,572],{"class":535},"    \u002F\u002F Dev-only debug members: only under WithExposeInternal(true), and only\n",[391,574,576],{"class":393,"line":575},11,[391,577,578],{"class":535},"    \u002F\u002F when the error carries an errs error. Always empty in production.\n",[391,580,582,585,587,589,592,595,597,600],{"class":393,"line":581},12,[391,583,584],{"class":439},"    Stack ",[391,586,545],{"class":401},[391,588,378],{"class":405},[391,590,591],{"class":401},".",[391,593,594],{"class":405},"Frame",[391,596,551],{"class":401},[391,598,599],{"class":450},"json:\"stack,omitempty\"",[391,601,454],{"class":401},[391,603,605,608,610,612,614,617,620,623],{"class":393,"line":604},13,[391,606,607],{"class":439},"    Chain ",[391,609,545],{"class":401},[391,611,378],{"class":405},[391,613,591],{"class":401},[391,615,616],{"class":405},"Step",[391,618,619],{"class":401},"  `",[391,621,622],{"class":450},"json:\"chain,omitempty\"",[391,624,454],{"class":401},[391,626,628],{"class":393,"line":627},14,[391,629,630],{"class":401},"}\n",[391,632,634],{"class":393,"line":633},15,[391,635,566],{"emptyLinePlaceholder":565},[391,637,639,641,644,646],{"class":393,"line":638},16,[391,640,424],{"class":401},[391,642,643],{"class":405}," FieldError",[391,645,430],{"class":401},[391,647,433],{"class":401},[391,649,651,654,656,658,661],{"class":393,"line":650},17,[391,652,653],{"class":439},"    Field   ",[391,655,444],{"class":443},[391,657,551],{"class":401},[391,659,660],{"class":450},"json:\"field\"",[391,662,454],{"class":401},[391,664,666,669,671,673,676],{"class":393,"line":665},18,[391,667,668],{"class":439},"    Rule    ",[391,670,444],{"class":443},[391,672,551],{"class":401},[391,674,675],{"class":450},"json:\"rule,omitempty\"",[391,677,454],{"class":401},[391,679,681,684,686,688,691],{"class":393,"line":680},19,[391,682,683],{"class":439},"    Message ",[391,685,444],{"class":443},[391,687,551],{"class":401},[391,689,690],{"class":450},"json:\"message\"",[391,692,454],{"class":401},[391,694,696],{"class":393,"line":695},20,[391,697,630],{"class":401},[348,699,700,703,704,707,708,711,712,715,716,719,720,724,725,728],{},[360,701,702],{},"Problem"," implements ",[360,705,706],{},"error",": you can return it directly from a handler or service, and it is rendered as-is at the end of the handler chain. When ",[360,709,710],{},"Instance"," is empty, the renderer stamps it with the request path. The ",[360,713,714],{},"Stack","\u002F",[360,717,718],{},"Chain"," members are deliberately ",[721,722,723],"strong",{},"not"," mirrored by the generated ",[360,726,727],{},"shared\u002Ferrors.tsp"," contract: clients must not depend on them, because they never appear in production.",[411,730,732],{"id":731},"constructors","Constructors",[382,734,736],{"className":384,"code":735,"language":386,"meta":387,"style":387},"httperr.New(status, title, detail) \u002F\u002F title defaults to the HTTP status text\nhttperr.BadRequest(detail)         \u002F\u002F 400        httperr.Unauthorized(detail) \u002F\u002F 401\nhttperr.Forbidden(detail)          \u002F\u002F 403        httperr.NotFound(detail)     \u002F\u002F 404\nhttperr.Conflict(detail)           \u002F\u002F 409        httperr.Internal(detail)     \u002F\u002F 500\nhttperr.Validation(fieldErrs...)   \u002F\u002F 422, with errors[]\n",[360,737,738,771,793,814,835],{"__ignoreMap":387},[391,739,740,742,744,748,751,754,757,760,762,765,768],{"class":393,"line":394},[391,741,366],{"class":439},[391,743,591],{"class":401},[391,745,747],{"class":746},"s2Zo4","New",[391,749,750],{"class":401},"(",[391,752,753],{"class":439},"status",[391,755,756],{"class":401},",",[391,758,759],{"class":439}," title",[391,761,756],{"class":401},[391,763,764],{"class":439}," detail",[391,766,767],{"class":401},")",[391,769,770],{"class":535}," \u002F\u002F title defaults to the HTTP status text\n",[391,772,773,775,777,780,782,785,787,790],{"class":393,"line":436},[391,774,366],{"class":439},[391,776,591],{"class":401},[391,778,779],{"class":746},"BadRequest",[391,781,750],{"class":401},[391,783,784],{"class":439},"detail",[391,786,767],{"class":401},[391,788,789],{"class":535},"         \u002F\u002F 400        httperr.Unauthorized(detail)",[391,791,792],{"class":535}," \u002F\u002F 401\n",[391,794,795,797,799,802,804,806,808,811],{"class":393,"line":457},[391,796,366],{"class":439},[391,798,591],{"class":401},[391,800,801],{"class":746},"Forbidden",[391,803,750],{"class":401},[391,805,784],{"class":439},[391,807,767],{"class":401},[391,809,810],{"class":535},"          \u002F\u002F 403        httperr.NotFound(detail)",[391,812,813],{"class":535},"     \u002F\u002F 404\n",[391,815,816,818,820,823,825,827,829,832],{"class":393,"line":472},[391,817,366],{"class":439},[391,819,591],{"class":401},[391,821,822],{"class":746},"Conflict",[391,824,750],{"class":401},[391,826,784],{"class":439},[391,828,767],{"class":401},[391,830,831],{"class":535},"           \u002F\u002F 409        httperr.Internal(detail)",[391,833,834],{"class":535},"     \u002F\u002F 500\n",[391,836,837,839,841,843,845,848,851],{"class":393,"line":489},[391,838,366],{"class":439},[391,840,591],{"class":401},[391,842,123],{"class":746},[391,844,750],{"class":401},[391,846,847],{"class":439},"fieldErrs",[391,849,850],{"class":401},"...)",[391,852,853],{"class":535},"   \u002F\u002F 422, with errors[]\n",[348,855,856,857,860,861,866],{},"They are meant for quick, anonymous 4xx cases: ",[360,858,859],{},"return httperr.NotFound(\"no such product\")"," in a handler is perfectly fine. As soon as an error mode has a name, a code or more than one occurrence, ",[352,862,863],{"href":79},[360,864,865],{},"errs.Define"," is the better home: there, recognition and rendering live in a single declaration.",[348,868,869,870,872,873,876,877,879],{},"Package-level ",[360,871,702],{}," sentinels (",[360,874,875],{},"var ErrX = httperr.NotFound(...)",") are safe: the renderers take a copy before stamping ",[360,878,710],{}," or dev members into it, so no state leaks across requests.",[411,881,883],{"id":882},"the-two-entry-points","The two entry points",[348,885,886,887,890],{},"The mapping is one; what differs per engine is only how it is hooked in. On Fiber, errors flow into the central ",[360,888,889],{},"ErrorHandler","; net\u002Fhttp has no such thing, so there the generated server code's error hooks call the writer functions.",[892,893,894,1001],"code-group",{},[382,895,898],{"className":384,"code":896,"filename":897,"language":386,"meta":387,"style":387},"\u002F\u002F fiberx.Run wires it into fiber.Config.ErrorHandler automatically:\nfunc NewErrorHandler(opts ...HandlerOption) fiber.ErrorHandler\nvar ErrorHandler fiber.ErrorHandler \u002F\u002F with default options, for manual wiring\n\n\u002F\u002F Options:\nhttperr.WithExposeInternal(true) \u002F\u002F 5xx detail + stack\u002Fchain in the response, dev only!\nhttperr.WithLogger(l)            \u002F\u002F logger for 5xx causes (default: slog.Default())\n","Fiber",[360,899,900,905,935,953,957,962,982],{"__ignoreMap":387},[391,901,902],{"class":393,"line":394},[391,903,904],{"class":535},"\u002F\u002F fiberx.Run wires it into fiber.Config.ErrorHandler automatically:\n",[391,906,907,910,913,915,919,922,925,927,930,932],{"class":393,"line":436},[391,908,909],{"class":401},"func",[391,911,912],{"class":746}," NewErrorHandler",[391,914,750],{"class":401},[391,916,918],{"class":917},"sHdIc","opts",[391,920,921],{"class":401}," ...",[391,923,924],{"class":405},"HandlerOption",[391,926,767],{"class":401},[391,928,929],{"class":405}," fiber",[391,931,591],{"class":401},[391,933,934],{"class":405},"ErrorHandler\n",[391,936,937,940,943,946,948,950],{"class":393,"line":457},[391,938,939],{"class":401},"var",[391,941,942],{"class":439}," ErrorHandler ",[391,944,945],{"class":405},"fiber",[391,947,591],{"class":401},[391,949,889],{"class":405},[391,951,952],{"class":535}," \u002F\u002F with default options, for manual wiring\n",[391,954,955],{"class":393,"line":472},[391,956,566],{"emptyLinePlaceholder":565},[391,958,959],{"class":393,"line":489},[391,960,961],{"class":535},"\u002F\u002F Options:\n",[391,963,964,966,968,971,973,977,979],{"class":393,"line":504},[391,965,366],{"class":439},[391,967,591],{"class":401},[391,969,970],{"class":746},"WithExposeInternal",[391,972,750],{"class":401},[391,974,976],{"class":975},"sfNiH","true",[391,978,767],{"class":401},[391,980,981],{"class":535}," \u002F\u002F 5xx detail + stack\u002Fchain in the response, dev only!\n",[391,983,984,986,988,991,993,996,998],{"class":393,"line":519},[391,985,366],{"class":439},[391,987,591],{"class":401},[391,989,990],{"class":746},"WithLogger",[391,992,750],{"class":401},[391,994,995],{"class":405},"l",[391,997,767],{"class":401},[391,999,1000],{"class":535},"            \u002F\u002F logger for 5xx causes (default: slog.Default())\n",[382,1002,1005],{"className":384,"code":1003,"filename":1004,"language":386,"meta":387,"style":387},"\u002F\u002F chix.Run wires it into the panic\u002F404\u002F405 handlers, the generated\n\u002F\u002F register.go into the strict server's error hooks:\nfunc NewWriteError(opts ...HandlerOption) func(http.ResponseWriter, *http.Request, error)\nfunc WriteError(w http.ResponseWriter, r *http.Request, err error) \u002F\u002F with default options\n\n\u002F\u002F For binding\u002Fdecoding hooks, where every error is a client error:\nfunc WriteBadRequest(w http.ResponseWriter, r *http.Request, err error)\n","chi",[360,1006,1007,1012,1017,1065,1109,1113,1118],{"__ignoreMap":387},[391,1008,1009],{"class":393,"line":394},[391,1010,1011],{"class":535},"\u002F\u002F chix.Run wires it into the panic\u002F404\u002F405 handlers, the generated\n",[391,1013,1014],{"class":393,"line":436},[391,1015,1016],{"class":535},"\u002F\u002F register.go into the strict server's error hooks:\n",[391,1018,1019,1021,1024,1026,1028,1030,1032,1034,1037,1040,1042,1045,1047,1050,1052,1054,1057,1059,1062],{"class":393,"line":457},[391,1020,909],{"class":401},[391,1022,1023],{"class":746}," NewWriteError",[391,1025,750],{"class":401},[391,1027,918],{"class":917},[391,1029,921],{"class":401},[391,1031,924],{"class":405},[391,1033,767],{"class":401},[391,1035,1036],{"class":401}," func(",[391,1038,1039],{"class":405},"http",[391,1041,591],{"class":401},[391,1043,1044],{"class":405},"ResponseWriter",[391,1046,756],{"class":401},[391,1048,1049],{"class":401}," *",[391,1051,1039],{"class":405},[391,1053,591],{"class":401},[391,1055,1056],{"class":405},"Request",[391,1058,756],{"class":401},[391,1060,1061],{"class":443}," error",[391,1063,1064],{"class":401},")\n",[391,1066,1067,1069,1072,1074,1077,1080,1082,1084,1086,1089,1091,1093,1095,1097,1099,1102,1104,1106],{"class":393,"line":472},[391,1068,909],{"class":401},[391,1070,1071],{"class":746}," WriteError",[391,1073,750],{"class":401},[391,1075,1076],{"class":917},"w",[391,1078,1079],{"class":405}," http",[391,1081,591],{"class":401},[391,1083,1044],{"class":405},[391,1085,756],{"class":401},[391,1087,1088],{"class":917}," r",[391,1090,1049],{"class":401},[391,1092,1039],{"class":405},[391,1094,591],{"class":401},[391,1096,1056],{"class":405},[391,1098,756],{"class":401},[391,1100,1101],{"class":917}," err",[391,1103,1061],{"class":443},[391,1105,767],{"class":401},[391,1107,1108],{"class":535}," \u002F\u002F with default options\n",[391,1110,1111],{"class":393,"line":489},[391,1112,566],{"emptyLinePlaceholder":565},[391,1114,1115],{"class":393,"line":504},[391,1116,1117],{"class":535},"\u002F\u002F For binding\u002Fdecoding hooks, where every error is a client error:\n",[391,1119,1120,1122,1125,1127,1129,1131,1133,1135,1137,1139,1141,1143,1145,1147,1149,1151,1153],{"class":393,"line":519},[391,1121,909],{"class":401},[391,1123,1124],{"class":746}," WriteBadRequest",[391,1126,750],{"class":401},[391,1128,1076],{"class":917},[391,1130,1079],{"class":405},[391,1132,591],{"class":401},[391,1134,1044],{"class":405},[391,1136,756],{"class":401},[391,1138,1088],{"class":917},[391,1140,1049],{"class":401},[391,1142,1039],{"class":405},[391,1144,591],{"class":401},[391,1146,1056],{"class":405},[391,1148,756],{"class":401},[391,1150,1101],{"class":917},[391,1152,1061],{"class":443},[391,1154,1064],{"class":401},[348,1156,1157,1160,1161,1164,1165,1168,1169,715,1172,1175,1176,1183,1184,1186,1187,1189,1190,1192],{},[360,1158,1159],{},"WriteError","'s signature deliberately matches oapi-codegen's ",[360,1162,1163],{},"ResponseErrorHandlerFunc"," hook, and ",[360,1166,1167],{},"WriteBadRequest"," the ",[360,1170,1171],{},"RequestErrorHandlerFunc",[360,1173,1174],{},"ErrorHandlerFunc"," hooks: the ",[352,1177,1179,1180],{"href":1178},"\u002Fen\u002Fhttp\u002Fchi#the-generated-wiring-registerapi","generated ",[360,1181,1182],{},"register.go"," wires them exactly like that. ",[360,1185,1167],{}," maps everything to 400 (except an already-built ",[360,1188,702],{}," and the 413 body-limit error), because a parameter-parse failure is never a 500. ",[360,1191,1159],{}," would misleadingly blame the server there.",[348,1194,1195,1196,1199,1200,1203,1204,1209,1210,1212],{},"Both engines pass the ",[360,1197,1198],{},"ExposeInternalErrors"," setting (",[360,1201,1202],{},"HTTP_EXPOSE_INTERNAL_ERRORS",") from ",[352,1205,1206],{"href":104},[360,1207,1208],{},"server.Config"," to their entry point: you only call ",[360,1211,970],{}," yourself when building the handler manually.",[411,1214,1216],{"id":1215},"the-mapping","The mapping",[348,1218,1219],{},"Both entry points run the same mapping, in this order:",[1221,1222,1223,1236],"table",{},[1224,1225,1226],"thead",{},[1227,1228,1229,1233],"tr",{},[1230,1231,1232],"th",{},"Error in the chain",[1230,1234,1235],{},"Response",[1237,1238,1239,1250,1267,1278,1288,1302,1329],"tbody",{},[1227,1240,1241,1247],{},[1242,1243,1244],"td",{},[360,1245,1246],{},"*httperr.Problem",[1242,1248,1249],{},"rendered as-is (a copy, the sentinel is never mutated)",[1227,1251,1252,1258],{},[1242,1253,1254,1255],{},"a validation failure from the ",[352,1256,1257],{"href":124},"validator",[1242,1259,1260,1261,1264,1265,767],{},"422 with per-field ",[360,1262,1263],{},"errors[]"," (the validator already returns a ",[360,1266,702],{},[1227,1268,1269,1275],{},[1242,1270,1271,1274],{},[360,1272,1273],{},"*fiber.BindError"," (malformed body\u002Fquery\u002Fheader)",[1242,1276,1277],{},"400",[1227,1279,1280,1285],{},[1242,1281,1282],{},[360,1283,1284],{},"*fiber.Error",[1242,1286,1287],{},"its own status code",[1227,1289,1290,1299],{},[1242,1291,1292,1295,1296,767],{},[360,1293,1294],{},"*http.MaxBytesError"," (body over ",[360,1297,1298],{},"BODY_LIMIT",[1242,1300,1301],{},"413",[1227,1303,1304,1311],{},[1242,1305,1306,1307,1061],{},"an ",[352,1308,1309],{"href":79},[360,1310,378],{},[1242,1312,1313,1316,1317,1319,1320,1323,1324,1319,1326],{},[360,1314,1315],{},"errs.StatusOf"," (500 when unset); ",[360,1318,784],{}," = ",[360,1321,1322],{},"errs.PublicOf",", ",[360,1325,360],{},[360,1327,1328],{},"errs.CodeOf",[1227,1330,1331,1334],{},[1242,1332,1333],{},"anything else",[1242,1335,1336,1337],{},"500, with no ",[360,1338,784],{},[348,1340,1341],{},"Two cross-cutting rules complete it:",[1343,1344,1345,1374],"ul",{},[1346,1347,1348,1351,1352,1355,1356,1358,1359,1362,1363,1365,1366,1369,1370,1373],"li",{},[721,1349,1350],{},"Every 5xx is logged",": the underlying error goes to ",[360,1353,1354],{},"slog"," with the request's method, path and trace context; for an ",[360,1357,378],{}," error, together with its structured chain and stack. A status-mapped ",[721,1360,1361],{},"4xx"," ",[360,1364,378],{}," error (e.g. a definition declared with ",[360,1367,1368],{},"errs.Status(404)",") produces ",[721,1371,1372],{},"no"," log line and no Sentry event: expected client behavior is not an incident.",[1346,1375,1376,1379,1380,1168,1383,1385,1386,1388,1389,1392,1393,1396],{},[721,1377,1378],{},"Dev mode shows more",": under ",[360,1381,1382],{},"WithExposeInternal(true)",[360,1384,784],{}," of unknown errors is filled in, and when the chain carries an ",[360,1387,378],{}," error, the response gains ",[360,1390,1391],{},"stack"," and ",[360,1394,1395],{},"chain"," extension members. In production the client never sees internals.",[348,1398,1399,1400,1402],{},"A recovered panic arrives here as an ",[360,1401,378],{}," error on both engines (its stack points at the panic site), so it renders and logs exactly like any other 500.",[411,1404,1406],{"id":1405},"the-shop-what-the-client-sees-when-stock-runs-out","The shop: what the client sees when stock runs out",[348,1408,1409,1410,1413,1414,1417,1418,1323,1421,1424,1425,1427,1428,1431],{},"The ",[360,1411,1412],{},"PlaceOrder"," service returns the ",[360,1415,1416],{},"ErrOutOfStock"," definition (",[360,1419,1420],{},"errs.Status(409)",[360,1422,1423],{},"errs.Public(...)","; see the declaration on the ",[352,1426,78],{"href":79}," page). By the time the ",[360,1429,1430],{},"POST \u002Fapi\u002Fv1\u002Fshop\u002Forders"," response goes out:",[382,1433,1437],{"className":1434,"code":1435,"language":1436,"meta":387,"style":387},"language-json shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","{\n  \"type\": \"about:blank\",\n  \"title\": \"Conflict\",\n  \"status\": 409,\n  \"detail\": \"The product is out of stock.\",\n  \"instance\": \"\u002Fapi\u002Fv1\u002Fshop\u002Forders\",\n  \"code\": \"shop_api_out_of_stock\"\n}\n","json",[360,1438,1439,1444,1467,1486,1502,1521,1541,1558],{"__ignoreMap":387},[391,1440,1441],{"class":393,"line":394},[391,1442,1443],{"class":401},"{\n",[391,1445,1446,1449,1451,1454,1457,1459,1462,1464],{"class":393,"line":436},[391,1447,1448],{"class":401},"  \"",[391,1450,424],{"class":443},[391,1452,1453],{"class":401},"\"",[391,1455,1456],{"class":401},":",[391,1458,402],{"class":401},[391,1460,1461],{"class":450},"about:blank",[391,1463,1453],{"class":401},[391,1465,1466],{"class":401},",\n",[391,1468,1469,1471,1474,1476,1478,1480,1482,1484],{"class":393,"line":457},[391,1470,1448],{"class":401},[391,1472,1473],{"class":443},"title",[391,1475,1453],{"class":401},[391,1477,1456],{"class":401},[391,1479,402],{"class":401},[391,1481,822],{"class":450},[391,1483,1453],{"class":401},[391,1485,1466],{"class":401},[391,1487,1488,1490,1492,1494,1496,1500],{"class":393,"line":472},[391,1489,1448],{"class":401},[391,1491,753],{"class":443},[391,1493,1453],{"class":401},[391,1495,1456],{"class":401},[391,1497,1499],{"class":1498},"sbssI"," 409",[391,1501,1466],{"class":401},[391,1503,1504,1506,1508,1510,1512,1514,1517,1519],{"class":393,"line":489},[391,1505,1448],{"class":401},[391,1507,784],{"class":443},[391,1509,1453],{"class":401},[391,1511,1456],{"class":401},[391,1513,402],{"class":401},[391,1515,1516],{"class":450},"The product is out of stock.",[391,1518,1453],{"class":401},[391,1520,1466],{"class":401},[391,1522,1523,1525,1528,1530,1532,1534,1537,1539],{"class":393,"line":504},[391,1524,1448],{"class":401},[391,1526,1527],{"class":443},"instance",[391,1529,1453],{"class":401},[391,1531,1456],{"class":401},[391,1533,402],{"class":401},[391,1535,1536],{"class":450},"\u002Fapi\u002Fv1\u002Fshop\u002Forders",[391,1538,1453],{"class":401},[391,1540,1466],{"class":401},[391,1542,1543,1545,1547,1549,1551,1553,1556],{"class":393,"line":519},[391,1544,1448],{"class":401},[391,1546,360],{"class":443},[391,1548,1453],{"class":401},[391,1550,1456],{"class":401},[391,1552,402],{"class":401},[391,1554,1555],{"class":450},"shop_api_out_of_stock",[391,1557,409],{"class":401},[391,1559,1560],{"class":393,"line":539},[391,1561,630],{"class":401},[1343,1563,1564,1572,1583,1594],{},[1346,1565,375,1566,1569,1570,756],{},[721,1567,1568],{},"409"," came from ",[360,1571,1315],{},[1346,1573,375,1574,1578,1579,1582],{},[721,1575,1576],{},[360,1577,784],{}," is the public message: the internal ",[360,1580,1581],{},"Error()"," text (query, wrap chain) never lands here,",[1346,1584,375,1585,1589,1590,1593],{},[721,1586,1587],{},[360,1588,360],{}," is stable and machine-readable: the frontend can branch on it (",[360,1591,1592],{},"if (body.code === \"shop_api_out_of_stock\")","), independent of message-text changes,",[1346,1595,1596,1597,1600],{},"log and Sentry: ",[721,1598,1599],{},"nothing"," (a status-mapped 4xx).",[348,1602,1603,1604,1607],{},"If the same call fails on a database error instead, the client gets a 500 with the ",[360,1605,1606],{},"shop_api_place_order_failed"," code and the generic public message, while the full chain and stack land in the log and in Sentry.",[411,1609,1611],{"id":1610},"render-and-report-in-a-single-mapping","Render and report in a single mapping",[348,1613,1614,1615,1618,1619,715,1622,715,1625,1628,1629,1632,1633,1635],{},"What the client sees (render) and what goes to the log\u002FSentry (report) lives in ",[721,1616,1617],{},"one"," central mapping: the render side is the table above (its input being ",[360,1620,1621],{},"errs.Status",[360,1623,1624],{},"Public",[360,1626,1627],{},"Code","), the report side is the automatic 5xx logging and the ",[352,1630,1631],{"href":238},"Sentry integration",". You don't write any per-error render logic: the error mode's declaration (",[360,1634,865],{},") carries everything the mapping works from.",[1637,1638,1639,1640,1643,1644,1647,1648,1652],"warning",{},"Don't bypass the mapping with hand-written ",[360,1641,1642],{},"c.Status(500).JSON(...)"," \u002F ",[360,1645,1646],{},"w.WriteHeader(500)"," responses in handlers. Return an error instead: that keeps the response shape, the logging and the Sentry reporting consistent, and your ",[352,1649,1651],{"href":1650},"\u002Fen\u002Fhttp\u002Ffiber#testing","tests"," see the same thing the client does.",[411,1654,1656],{"id":1655},"patterns-used","Patterns used",[1343,1658,1659,1671],{},[1346,1660,1661,1664,1665,1667,1668,591],{},[721,1662,1663],{},"RFC 9457 Problem Details",": the ",[360,1666,702],{}," struct and the standard itself, see ",[352,1669,92],{"href":1670},"\u002Fen\u002Fconcepts\u002Fdesign-patterns#rfc-9457-problem-details",[1346,1672,1673,1680,1681,1684,1685,591],{},[721,1674,1675,1676,1679],{},"Cascading ",[360,1677,1678],{},"errors.As"," mapping"," in ",[360,1682,1683],{},"mapProblem",": ",[352,1686,92],{"href":1687},"\u002Fen\u002Fconcepts\u002Fdesign-patterns#cascading-errorsas-mapping",[348,1689,1690,1691,591],{},"The official standard text: ",[352,1692,1694],{"href":354,"rel":1693},[356],"RFC 9457: Problem Details for HTTP APIs",[1696,1697,1698],"style",{},"html pre.shiki code .s7zQu, html code.shiki .s7zQu{--shiki-light:#39ADB5;--shiki-light-font-style:italic;--shiki-default:#89DDFF;--shiki-default-font-style:italic;--shiki-dark:#89DDFF;--shiki-dark-font-style:italic}html pre.shiki code .sMK4o, html code.shiki .sMK4o{--shiki-light:#39ADB5;--shiki-default:#89DDFF;--shiki-dark:#89DDFF}html pre.shiki code .sBMFI, html code.shiki .sBMFI{--shiki-light:#E2931D;--shiki-default:#FFCB6B;--shiki-dark:#FFCB6B}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .sTEyZ, html code.shiki .sTEyZ{--shiki-light:#90A4AE;--shiki-default:#EEFFFF;--shiki-dark:#BABED8}html pre.shiki code .spNyl, html code.shiki .spNyl{--shiki-light:#9C3EDA;--shiki-default:#C792EA;--shiki-dark:#C792EA}html pre.shiki code .sfazB, html code.shiki .sfazB{--shiki-light:#91B859;--shiki-default:#C3E88D;--shiki-dark:#C3E88D}html pre.shiki code .sHwdD, html code.shiki .sHwdD{--shiki-light:#90A4AE;--shiki-light-font-style:italic;--shiki-default:#546E7A;--shiki-default-font-style:italic;--shiki-dark:#676E95;--shiki-dark-font-style:italic}html pre.shiki code .s2Zo4, html code.shiki .s2Zo4{--shiki-light:#6182B8;--shiki-default:#82AAFF;--shiki-dark:#82AAFF}html pre.shiki code .sHdIc, html code.shiki .sHdIc{--shiki-light:#90A4AE;--shiki-light-font-style:italic;--shiki-default:#EEFFFF;--shiki-default-font-style:italic;--shiki-dark:#BABED8;--shiki-dark-font-style:italic}html pre.shiki code .sfNiH, html code.shiki .sfNiH{--shiki-light:#FF5370;--shiki-default:#FF9CAC;--shiki-dark:#FF9CAC}html pre.shiki code .sbssI, html code.shiki .sbssI{--shiki-light:#F76D47;--shiki-default:#F78C6C;--shiki-dark:#F78C6C}",{"title":387,"searchDepth":436,"depth":436,"links":1700},[1701,1702,1703,1704,1705,1706,1707],{"id":413,"depth":436,"text":414},{"id":731,"depth":436,"text":732},{"id":882,"depth":436,"text":883},{"id":1215,"depth":436,"text":1216},{"id":1405,"depth":436,"text":1406},{"id":1610,"depth":436,"text":1611},{"id":1655,"depth":436,"text":1656},"The httperr package, RFC 9457 problem+json for every error, through one central mapping, on both engines.","md",null,{},{"icon":121},{"title":118,"description":1708},"hix4k4lXEC8FUG7TgH0VLcmrk7b-U2zavvSVJLheGrU",[1716,1718],{"title":113,"path":114,"stem":115,"description":1717,"icon":116,"children":-1},"server\u002Fchix, a chi router over the standard net\u002Fhttp with the kit's error handling and telemetry wired in, run with graceful shutdown.",{"title":123,"path":124,"stem":125,"description":1719,"icon":126,"children":-1},"Struct-tag-based request validation with go-playground\u002Fvalidator, at bind time on Fiber, as strict middleware on chi, with 422 problem responses.",1784668707586]