[{"data":1,"prerenderedAt":1540},["ShallowReactive",2],{"navigation_docs_en":3,"-en-httperr-error-responses":441,"-en-httperr-error-responses-surround":1535},[4,45,60,81,112,129,146,173,197,213,242,279,356,372,384,403,429],{"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},"queue","i-lucide-layers","\u002Fen\u002Fqueue","en\u002F10.queue",[51,56],{"title":52,"path":53,"stem":54,"icon":55},"Overview","\u002Fen\u002Fqueue\u002Foverview","en\u002F10.queue\u002F1.overview","i-lucide-list-ordered",{"title":57,"path":58,"stem":59,"icon":47},"Tasks","\u002Fen\u002Fqueue\u002Ftasks","en\u002F10.queue\u002F2.tasks",{"title":61,"icon":62,"path":63,"stem":64,"children":65,"page":44},"events","i-lucide-workflow","\u002Fen\u002Fevents","en\u002F11.events",[66,71,76],{"title":67,"path":68,"stem":69,"icon":70},"Events","\u002Fen\u002Fevents\u002Foverview","en\u002F11.events\u002F1.overview","i-lucide-radio",{"title":72,"path":73,"stem":74,"icon":75},"Outbox","\u002Fen\u002Fevents\u002Foutbox","en\u002F11.events\u002F2.outbox","i-lucide-inbox",{"title":77,"path":78,"stem":79,"icon":80},"Scheduling","\u002Fen\u002Fevents\u002Fscheduler","en\u002F11.events\u002F3.scheduler","i-lucide-calendar-clock",{"title":82,"icon":83,"path":84,"stem":85,"children":86,"page":44},"auth","i-lucide-shield-check","\u002Fen\u002Fauth","en\u002F12.auth",[87,92,97,102,107],{"title":88,"path":89,"stem":90,"icon":91},"Authentication","\u002Fen\u002Fauth\u002Foverview","en\u002F12.auth\u002F1.overview","i-lucide-key-round",{"title":93,"path":94,"stem":95,"icon":96},"RBAC","\u002Fen\u002Fauth\u002Frbac","en\u002F12.auth\u002F2.rbac","i-lucide-users",{"title":98,"path":99,"stem":100,"icon":101},"Policies","\u002Fen\u002Fauth\u002Fpolicy","en\u002F12.auth\u002F3.policy","i-lucide-gavel",{"title":103,"path":104,"stem":105,"icon":106},"Using auth standalone","\u002Fen\u002Fauth\u002Fstandalone","en\u002F12.auth\u002F4.standalone","i-lucide-plug",{"title":108,"path":109,"stem":110,"icon":111},"Social login with goth, standalone","\u002Fen\u002Fauth\u002Fsocial-standalone","en\u002F12.auth\u002F5.social-standalone","i-lucide-log-in",{"title":113,"icon":114,"path":115,"stem":116,"children":117,"page":44},"mail","i-lucide-mail","\u002Fen\u002Fmail","en\u002F13.mail",[118,121,125],{"title":52,"path":119,"stem":120,"icon":114},"\u002Fen\u002Fmail\u002Foverview","en\u002F13.mail\u002F1.overview",{"title":122,"path":123,"stem":124,"icon":114},"SMTP","\u002Fen\u002Fmail\u002Fsmtp","en\u002F13.mail\u002F2.smtp",{"title":126,"path":127,"stem":128,"icon":114},"MJML","\u002Fen\u002Fmail\u002Fmjml","en\u002F13.mail\u002F3.mjml",{"title":130,"icon":131,"path":132,"stem":133,"children":134,"page":44},"notify","i-lucide-bell","\u002Fen\u002Fnotify","en\u002F14.notify",[135,138,142],{"title":52,"path":136,"stem":137,"icon":131},"\u002Fen\u002Fnotify\u002Foverview","en\u002F14.notify\u002F1.overview",{"title":139,"path":140,"stem":141,"icon":131},"Database channel","\u002Fen\u002Fnotify\u002Fdatabase","en\u002F14.notify\u002F2.database",{"title":143,"path":144,"stem":145,"icon":131},"Broadcast channel","\u002Fen\u002Fnotify\u002Fbroadcast","en\u002F14.notify\u002F3.broadcast",{"title":147,"icon":148,"path":149,"stem":150,"children":151,"page":44},"storage","i-lucide-hard-drive","\u002Fen\u002Fstorage","en\u002F15.storage",[152,155,159,163,168],{"title":52,"path":153,"stem":154,"icon":148},"\u002Fen\u002Fstorage\u002Foverview","en\u002F15.storage\u002F1.overview",{"title":156,"path":157,"stem":158},"Disk API","\u002Fen\u002Fstorage\u002Fdisk-api","en\u002F15.storage\u002F2.disk-api",{"title":160,"path":161,"stem":162,"icon":148},"Memory and local disk","\u002Fen\u002Fstorage\u002Flocal","en\u002F15.storage\u002F3.local",{"title":164,"path":165,"stem":166,"icon":167},"S3","\u002Fen\u002Fstorage\u002Fs3","en\u002F15.storage\u002F4.s3","i-lucide-cloud",{"title":169,"path":170,"stem":171,"icon":172},"Testing","\u002Fen\u002Fstorage\u002Ftesting","en\u002F15.storage\u002F5.testing","i-lucide-flask-conical",{"title":174,"icon":175,"path":176,"stem":177,"children":178,"page":44},"telemetry","i-lucide-activity","\u002Fen\u002Ftelemetry","en\u002F16.telemetry",[179,182,187,192],{"title":52,"path":180,"stem":181,"icon":175},"\u002Fen\u002Ftelemetry\u002Foverview","en\u002F16.telemetry\u002F1.overview",{"title":183,"path":184,"stem":185,"icon":186},"Logging","\u002Fen\u002Ftelemetry\u002Flogging","en\u002F16.telemetry\u002F2.logging","i-lucide-scroll-text",{"title":188,"path":189,"stem":190,"icon":191},"OpenTelemetry","\u002Fen\u002Ftelemetry\u002Fopentelemetry","en\u002F16.telemetry\u002F3.opentelemetry","i-lucide-radar",{"title":193,"path":194,"stem":195,"icon":196},"Sentry","\u002Fen\u002Ftelemetry\u002Fsentry","en\u002F16.telemetry\u002F4.sentry","i-lucide-bug",{"title":198,"icon":199,"path":200,"stem":201,"children":202,"page":44},"Reference","i-lucide-book-open","\u002Fen\u002Freference","en\u002F17.reference",[203,208],{"title":204,"path":205,"stem":206,"icon":207},"Configuration","\u002Fen\u002Freference\u002Fconfiguration","en\u002F17.reference\u002F1.configuration","i-lucide-settings",{"title":209,"path":210,"stem":211,"icon":212},"External dependencies","\u002Fen\u002Freference\u002Fdependencies","en\u002F17.reference\u002F2.dependencies","i-lucide-package",{"title":214,"icon":215,"path":216,"stem":217,"children":218,"page":44},"Concepts","i-lucide-lightbulb","\u002Fen\u002Fconcepts","en\u002F2.concepts",[219,223,228,232,237],{"title":220,"path":221,"stem":222,"icon":47},"Architecture","\u002Fen\u002Fconcepts\u002Farchitecture","en\u002F2.concepts\u002F1.architecture",{"title":224,"path":225,"stem":226,"icon":227},"Error model","\u002Fen\u002Fconcepts\u002Ferror-model","en\u002F2.concepts\u002F2.error-model","i-lucide-shield-alert",{"title":204,"path":229,"stem":230,"icon":231},"\u002Fen\u002Fconcepts\u002Fconfiguration","en\u002F2.concepts\u002F3.configuration","i-lucide-settings-2",{"title":233,"path":234,"stem":235,"icon":236},"Codegen pipeline","\u002Fen\u002Fconcepts\u002Fcodegen-pipeline","en\u002F2.concepts\u002F4.codegen-pipeline","i-lucide-file-json",{"title":238,"path":239,"stem":240,"icon":241},"Design patterns","\u002Fen\u002Fconcepts\u002Fdesign-patterns","en\u002F2.concepts\u002F5.design-patterns","i-lucide-puzzle",{"title":243,"icon":244,"path":245,"stem":246,"children":247,"page":44},"Kit","i-lucide-box","\u002Fen\u002Fkit","en\u002F3.kit",[248,251,256,261,266,270,275],{"title":52,"path":249,"stem":250,"icon":244},"\u002Fen\u002Fkit\u002Foverview","en\u002F3.kit\u002F1.overview",{"title":252,"path":253,"stem":254,"icon":255},"Application lifecycle","\u002Fen\u002Fkit\u002Fapp","en\u002F3.kit\u002F2.app","i-lucide-power",{"title":257,"path":258,"stem":259,"icon":260},"Server","\u002Fen\u002Fkit\u002Fserver","en\u002F3.kit\u002F3.server","i-lucide-server",{"title":262,"path":263,"stem":264,"icon":265},"Worker","\u002Fen\u002Fkit\u002Fworker","en\u002F3.kit\u002F4.worker","i-lucide-cog",{"title":267,"path":268,"stem":269,"icon":70},"Realtime","\u002Fen\u002Fkit\u002Frealtime","en\u002F3.kit\u002F5.realtime",{"title":271,"path":272,"stem":273,"icon":274},"Migrations","\u002Fen\u002Fkit\u002Fmigrations","en\u002F3.kit\u002F6.migrations","i-lucide-file-stack",{"title":276,"path":277,"stem":278,"icon":111},"Social login","\u002Fen\u002Fkit\u002Fsocial-login","en\u002F3.kit\u002F7.social-login",{"title":280,"icon":281,"path":282,"stem":283,"children":284,"page":44},"CLI Reference","i-lucide-terminal","\u002Fen\u002Fcli","en\u002F4.cli",[285,288,293,298,303,308,313,318,323,328,333,337,342,347,351],{"title":52,"path":286,"stem":287,"icon":281},"\u002Fen\u002Fcli\u002Foverview","en\u002F4.cli\u002F1.overview",{"title":289,"path":290,"stem":291,"icon":292},"add db","\u002Fen\u002Fcli\u002Fadd-db","en\u002F4.cli\u002F10.add-db","i-lucide-database-zap",{"title":294,"path":295,"stem":296,"icon":297},"add compose \u002F add docker","\u002Fen\u002Fcli\u002Fadd-compose","en\u002F4.cli\u002F11.add-compose","i-lucide-container",{"title":299,"path":300,"stem":301,"icon":302},"add mail","\u002Fen\u002Fcli\u002Fadd-mail","en\u002F4.cli\u002F12.add-mail","i-lucide-mail-plus",{"title":304,"path":305,"stem":306,"icon":307},"add notification","\u002Fen\u002Fcli\u002Fadd-notification","en\u002F4.cli\u002F13.add-notification","i-lucide-bell-plus",{"title":309,"path":310,"stem":311,"icon":312},"add realtime","\u002Fen\u002Fcli\u002Fadd-realtime","en\u002F4.cli\u002F14.add-realtime","i-lucide-radio-tower",{"title":314,"path":315,"stem":316,"icon":317},"add seeder","\u002Fen\u002Fcli\u002Fadd-seeder","en\u002F4.cli\u002F15.add-seeder","i-lucide-sprout",{"title":319,"path":320,"stem":321,"icon":322},"new project","\u002Fen\u002Fcli\u002Fnew-project","en\u002F4.cli\u002F2.new-project","i-lucide-folder-plus",{"title":324,"path":325,"stem":326,"icon":327},"new module","\u002Fen\u002Fcli\u002Fnew-module","en\u002F4.cli\u002F3.new-module","i-lucide-blocks",{"title":329,"path":330,"stem":331,"icon":332},"add surface","\u002Fen\u002Fcli\u002Fadd-surface","en\u002F4.cli\u002F4.add-surface","i-lucide-layers-2",{"title":334,"path":335,"stem":336,"icon":244},"add core","\u002Fen\u002Fcli\u002Fadd-core","en\u002F4.cli\u002F5.add-core",{"title":338,"path":339,"stem":340,"icon":341},"add handler","\u002Fen\u002Fcli\u002Fadd-handler","en\u002F4.cli\u002F6.add-handler","i-lucide-webhook",{"title":343,"path":344,"stem":345,"icon":346},"new migration","\u002Fen\u002Fcli\u002Fnew-migration","en\u002F4.cli\u002F7.new-migration","i-lucide-file-plus",{"title":348,"path":349,"stem":350,"icon":265},"worker generators","\u002Fen\u002Fcli\u002Fworker-generators","en\u002F4.cli\u002F8.worker-generators",{"title":352,"path":353,"stem":354,"icon":355},"upgrade templates","\u002Fen\u002Fcli\u002Fupgrade-templates","en\u002F4.cli\u002F9.upgrade-templates","i-lucide-refresh-cw",{"title":357,"icon":227,"path":358,"stem":359,"children":360,"page":44},"errs","\u002Fen\u002Ferrs","en\u002F5.errs",[361,364,368],{"title":52,"path":362,"stem":363,"icon":227},"\u002Fen\u002Ferrs\u002Foverview","en\u002F5.errs\u002F1.overview",{"title":365,"path":366,"stem":367},"API","\u002Fen\u002Ferrs\u002Fapi","en\u002F5.errs\u002F2.api",{"title":369,"path":370,"stem":371,"icon":227},"Integration","\u002Fen\u002Ferrs\u002Fintegration","en\u002F5.errs\u002F3.integration",{"title":373,"icon":231,"path":374,"stem":375,"children":376,"page":44},"envconf","\u002Fen\u002Fenvconf","en\u002F6.envconf",[377,380],{"title":52,"path":378,"stem":379,"icon":231},"\u002Fen\u002Fenvconf\u002Foverview","en\u002F6.envconf\u002F1.overview",{"title":381,"path":382,"stem":383},"Recipes","\u002Fen\u002Fenvconf\u002Frecipes","en\u002F6.envconf\u002F2.recipes",{"title":385,"icon":386,"path":387,"stem":388,"children":389,"page":44},"httperr","i-lucide-globe","\u002Fen\u002Fhttperr","en\u002F7.httperr",[390,393,398],{"title":52,"path":391,"stem":392,"icon":386},"\u002Fen\u002Fhttperr\u002Foverview","en\u002F7.httperr\u002F1.overview",{"title":394,"path":395,"stem":396,"icon":397},"Error responses","\u002Fen\u002Fhttperr\u002Ferror-responses","en\u002F7.httperr\u002F2.error-responses","i-lucide-octagon-alert",{"title":399,"path":400,"stem":401,"icon":402},"Validation","\u002Fen\u002Fhttperr\u002Fvalidation","en\u002F7.httperr\u002F3.validation","i-lucide-badge-check",{"title":404,"icon":405,"path":406,"stem":407,"children":408,"page":44},"dbx","i-lucide-database","\u002Fen\u002Fdbx","en\u002F8.dbx",[409,412,416,420,425],{"title":52,"path":410,"stem":411,"icon":405},"\u002Fen\u002Fdbx\u002Foverview","en\u002F8.dbx\u002F1.overview",{"title":413,"path":414,"stem":415,"icon":106},"pgx","\u002Fen\u002Fdbx\u002Fpg","en\u002F8.dbx\u002F2.pg",{"title":417,"path":418,"stem":419,"icon":47},"bun","\u002Fen\u002Fdbx\u002Fbunx","en\u002F8.dbx\u002F3.bunx",{"title":421,"path":422,"stem":423,"icon":424},"Transactions","\u002Fen\u002Fdbx\u002Ftransactions","en\u002F8.dbx\u002F4.transactions","i-lucide-git-merge",{"title":426,"path":427,"stem":428,"icon":317},"Seeders","\u002Fen\u002Fdbx\u002Fseed","en\u002F8.dbx\u002F5.seed",{"title":430,"icon":55,"path":431,"stem":432,"children":433,"page":44},"paginate","\u002Fen\u002Fpaginate","en\u002F9.paginate",[434,437],{"title":52,"path":435,"stem":436,"icon":55},"\u002Fen\u002Fpaginate\u002Foverview","en\u002F9.paginate\u002F1.overview",{"title":438,"path":439,"stem":440,"icon":19},"Cursor pagination","\u002Fen\u002Fpaginate\u002Fcursor","en\u002F9.paginate\u002F2.cursor",{"id":442,"title":394,"body":443,"description":1528,"extension":1529,"links":1530,"meta":1531,"navigation":1532,"path":395,"seo":1533,"stem":396,"__hash__":1534},"docs_en\u002Fen\u002F7.httperr\u002F2.error-responses.md",{"type":444,"value":445,"toc":1517},"minimark",[446,482,511,543,548,702,726,802,842,856,860,868,965,968,1047,1061,1065,1116,1120,1159,1163,1187,1324,1363,1370,1374,1396,1404,1408,1438,1442,1469,1476,1480,1513],[447,448,449,450,457,458,462,463,465,466,470,471,477,478,481],"p",{},"Every error a gpsystem service puts on the wire (a validation failure, a 404, a panic, a database timeout) is an ",[451,452,456],"a",{"href":453,"rel":454},"https:\u002F\u002Fwww.rfc-editor.org\u002Frfc\u002Frfc9457",[455],"nofollow","RFC 9457"," problem document with ",[459,460,461],"code",{},"Content-Type: application\u002Fproblem+json",". ",[459,464,385],{}," guarantees that: it is the wire-facing error shape and the single place where a Go error becomes an HTTP response. ",[467,468,469],"em",{},"Building"," errors (stack, code, public message) is covered by ",[451,472,473,474,476],{"href":225},"the ",[459,475,357],{}," package and the error model","; this page covers the rendering side, on plain ",[459,479,480],{},"net\u002Fhttp",".",[483,484,489],"pre",{"className":485,"code":486,"language":487,"meta":488,"style":488},"language-go shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","import \"github.com\u002Fgp-system\u002Fhttperr\"\n","go","",[459,490,491],{"__ignoreMap":488},[492,493,496,500,504,508],"span",{"class":494,"line":495},"line",1,[492,497,499],{"class":498},"s7zQu","import",[492,501,503],{"class":502},"sMK4o"," \"",[492,505,507],{"class":506},"sBMFI","github.com\u002Fgp-system\u002Fhttperr",[492,509,510],{"class":502},"\"\n",[447,512,513,514,517,518,521,522,525,526,525,529,531,532,534,535,539,540,542],{},"The ",[459,515,516],{},"Problem","\u002F",[459,519,520],{},"FieldError"," shape and the quick constructors (",[459,523,524],{},"BadRequest",", ",[459,527,528],{},"NotFound",[459,530,399],{},", ...) are on the ",[451,533,52],{"href":391}," page; this page is about turning ",[536,537,538],"strong",{},"any"," error, not just a hand-built ",[459,541,516],{},", into that shape.",[544,545,547],"h2",{"id":546},"writeerror-and-newwriteerror","WriteError and NewWriteError",[483,549,551],{"className":485,"code":550,"language":487,"meta":488,"style":488},"func WriteError(w http.ResponseWriter, r *http.Request, err error)              \u002F\u002F default options\nfunc NewWriteError(opts ...HandlerOption) func(http.ResponseWriter, *http.Request, error)\n\nfunc WriteBadRequest(w http.ResponseWriter, r *http.Request, err error)\n",[459,552,553,610,657,664],{"__ignoreMap":488},[492,554,555,558,562,565,569,572,574,577,580,583,586,589,591,594,596,599,603,606],{"class":494,"line":495},[492,556,557],{"class":502},"func",[492,559,561],{"class":560},"s2Zo4"," WriteError",[492,563,564],{"class":502},"(",[492,566,568],{"class":567},"sHdIc","w",[492,570,571],{"class":506}," http",[492,573,481],{"class":502},[492,575,576],{"class":506},"ResponseWriter",[492,578,579],{"class":502},",",[492,581,582],{"class":567}," r",[492,584,585],{"class":502}," *",[492,587,588],{"class":506},"http",[492,590,481],{"class":502},[492,592,593],{"class":506},"Request",[492,595,579],{"class":502},[492,597,598],{"class":567}," err",[492,600,602],{"class":601},"spNyl"," error",[492,604,605],{"class":502},")",[492,607,609],{"class":608},"sHwdD","              \u002F\u002F default options\n",[492,611,613,615,618,620,623,626,629,631,634,636,638,640,642,644,646,648,650,652,654],{"class":494,"line":612},2,[492,614,557],{"class":502},[492,616,617],{"class":560}," NewWriteError",[492,619,564],{"class":502},[492,621,622],{"class":567},"opts",[492,624,625],{"class":502}," ...",[492,627,628],{"class":506},"HandlerOption",[492,630,605],{"class":502},[492,632,633],{"class":502}," func(",[492,635,588],{"class":506},[492,637,481],{"class":502},[492,639,576],{"class":506},[492,641,579],{"class":502},[492,643,585],{"class":502},[492,645,588],{"class":506},[492,647,481],{"class":502},[492,649,593],{"class":506},[492,651,579],{"class":502},[492,653,602],{"class":601},[492,655,656],{"class":502},")\n",[492,658,660],{"class":494,"line":659},3,[492,661,663],{"emptyLinePlaceholder":662},true,"\n",[492,665,667,669,672,674,676,678,680,682,684,686,688,690,692,694,696,698,700],{"class":494,"line":666},4,[492,668,557],{"class":502},[492,670,671],{"class":560}," WriteBadRequest",[492,673,564],{"class":502},[492,675,568],{"class":567},[492,677,571],{"class":506},[492,679,481],{"class":502},[492,681,576],{"class":506},[492,683,579],{"class":502},[492,685,582],{"class":567},[492,687,585],{"class":502},[492,689,588],{"class":506},[492,691,481],{"class":502},[492,693,593],{"class":506},[492,695,579],{"class":502},[492,697,598],{"class":567},[492,699,602],{"class":601},[492,701,656],{"class":502},[447,703,704,707,708,712,713,715,716,462,719,722,723,725],{},[459,705,706],{},"WriteError"," runs the ",[451,709,711],{"href":710},"#the-mapping","mapping"," below and writes the resulting ",[459,714,516],{}," as ",[459,717,718],{},"application\u002Fproblem+json",[459,720,721],{},"NewWriteError"," builds a customized writer with ",[459,724,628],{},"s:",[483,727,729],{"className":485,"code":728,"language":487,"meta":488,"style":488},"type HandlerOption func(*handlerConfig)\n\nfunc WithExposeInternal(expose bool) HandlerOption \u002F\u002F 5xx detail + stack\u002Fchain in the response, dev only!\nfunc WithLogger(l *slog.Logger) HandlerOption      \u002F\u002F logger for 5xx causes (default: slog.Default())\n",[459,730,731,747,751,773],{"__ignoreMap":488},[492,732,733,736,739,742,745],{"class":494,"line":495},[492,734,735],{"class":502},"type",[492,737,738],{"class":506}," HandlerOption",[492,740,741],{"class":502}," func(*",[492,743,744],{"class":506},"handlerConfig",[492,746,656],{"class":502},[492,748,749],{"class":494,"line":612},[492,750,663],{"emptyLinePlaceholder":662},[492,752,753,755,758,760,763,766,768,770],{"class":494,"line":659},[492,754,557],{"class":502},[492,756,757],{"class":560}," WithExposeInternal",[492,759,564],{"class":502},[492,761,762],{"class":567},"expose",[492,764,765],{"class":601}," bool",[492,767,605],{"class":502},[492,769,738],{"class":506},[492,771,772],{"class":608}," \u002F\u002F 5xx detail + stack\u002Fchain in the response, dev only!\n",[492,774,775,777,780,782,785,787,790,792,795,797,799],{"class":494,"line":666},[492,776,557],{"class":502},[492,778,779],{"class":560}," WithLogger",[492,781,564],{"class":502},[492,783,784],{"class":567},"l",[492,786,585],{"class":502},[492,788,789],{"class":506},"slog",[492,791,481],{"class":502},[492,793,794],{"class":506},"Logger",[492,796,605],{"class":502},[492,798,738],{"class":506},[492,800,801],{"class":608},"      \u002F\u002F logger for 5xx causes (default: slog.Default())\n",[447,803,804,806,807,812,813,816,817,824,825,827,828,831,832,834,835,517,838,841],{},[459,805,706],{},"'s signature deliberately matches ",[451,808,811],{"href":809,"rel":810},"https:\u002F\u002Fgithub.com\u002Foapi-codegen\u002Foapi-codegen",[455],"oapi-codegen","'s strict-server ",[459,814,815],{},"ResponseErrorHandlerFunc"," hook, so the ",[451,818,820,821],{"href":819},"\u002Fen\u002Fkit\u002Fserver#registerfunc-and-strictvalidator","generated ",[459,822,823],{},"register.go"," wires it there directly: an error your handler returns goes through ",[459,826,706],{}," with no glue code in between. ",[459,829,830],{},"WriteBadRequest"," maps everything to 400, except an already-built ",[459,833,516],{}," and the 413 body-limit error, because a parameter-parse or body-decode failure is never a 500; it matches oapi-codegen's ",[459,836,837],{},"RequestErrorHandlerFunc",[459,839,840],{},"ErrorHandlerFunc"," hooks, used where decoding, not your handler, produced the error.",[447,843,844,845,847,848,851,852,855],{},"Package-level ",[459,846,516],{}," sentinels (",[459,849,850],{},"var ErrX = httperr.NotFound(...)",") are safe to write this way: the writers take a copy before stamping ",[459,853,854],{},"Instance"," or dev-mode members into it, so no state leaks across requests.",[544,857,859],{"id":858},"the-mapping","The mapping",[447,861,862,864,865,867],{},[459,863,706],{}," and ",[459,866,830],{}," run the same mapping, in this order:",[869,870,871,884],"table",{},[872,873,874],"thead",{},[875,876,877,881],"tr",{},[878,879,880],"th",{},"Error in the chain",[878,882,883],{},"Response",[885,886,887,898,917,928,955],"tbody",{},[875,888,889,895],{},[890,891,892],"td",{},[459,893,894],{},"*httperr.Problem",[890,896,897],{},"rendered as-is (a copy, the sentinel is never mutated)",[875,899,900,908],{},[890,901,902,903],{},"a validation failure from ",[451,904,905],{"href":400},[459,906,907],{},"httperr\u002Fvalidate",[890,909,910,911,914,915,605],{},"422 with per-field ",[459,912,913],{},"errors[]"," (the validator already returns a ",[459,916,516],{},[875,918,919,925],{},[890,920,921,924],{},[459,922,923],{},"*http.MaxBytesError"," (body over the configured limit)",[890,926,927],{},"413",[875,929,930,937],{},[890,931,932,933,602],{},"an ",[451,934,935],{"href":225},[459,936,357],{},[890,938,939,942,943,946,947,525,950,946,952],{},[459,940,941],{},"errs.StatusOf"," (500 when unset); ",[459,944,945],{},"detail"," = ",[459,948,949],{},"errs.PublicOf",[459,951,459],{},[459,953,954],{},"errs.CodeOf",[875,956,957,960],{},[890,958,959],{},"anything else",[890,961,962,963],{},"500, with no ",[459,964,945],{},[447,966,967],{},"Two cross-cutting rules complete it:",[969,970,971,1012],"ul",{},[972,973,974,977,978,980,981,984,985,988,989,991,992,996,997,1000,1001,1003,1004,1007,1008,1011],"li",{},[536,975,976],{},"Every 5xx is logged",": the underlying error goes to ",[459,979,789],{}," (via ",[459,982,983],{},"WithLogger","'s logger, ",[459,986,987],{},"slog.Default()"," otherwise) with the request's method, path and trace context; for an ",[459,990,357],{}," error, together with its structured chain and stack (see ",[451,993,995],{"href":994},"\u002Fen\u002Ferrs\u002Fintegration#log-output","errs: Integration","). A status-mapped ",[536,998,999],{},"4xx"," ",[459,1002,357],{}," error (e.g. a definition declared with ",[459,1005,1006],{},"errs.Status(404)",") produces ",[536,1009,1010],{},"no"," log line and no Sentry event: expected client behavior is not an incident.",[972,1013,1014,1017,1018,1021,1022,1024,1025,1027,1028,864,1031,1034,1035,517,1038,1041,1042,1046],{},[536,1015,1016],{},"Dev mode shows more",": under ",[459,1019,1020],{},"WithExposeInternal(true)"," the ",[459,1023,945],{}," of unknown errors is filled in, and when the chain carries an ",[459,1026,357],{}," error, the response gains ",[459,1029,1030],{},"stack",[459,1032,1033],{},"chain"," extension members (",[459,1036,1037],{},"errs.Frames",[459,1039,1040],{},"errs.Chain",", see ",[451,1043,1045],{"href":1044},"\u002Fen\u002Ferrs\u002Fapi#introspection-frames-fullframes-chain","errs: API","). In production the client never sees internals.",[447,1048,1049,1050,1053,1054,1060],{},"A recovered panic, turned into an ",[459,1051,1052],{},"*errs.Error"," with ",[451,1055,1057],{"href":1056},"\u002Fen\u002Ferrs\u002Fapi#constructors",[459,1058,1059],{},"errs.NewPanic"," (its stack pointing at the panic site), renders and logs exactly like any other 500 once it reaches this mapping.",[544,1062,1064],{"id":1063},"errs-integration","errs integration",[447,1066,1067,1068,1070,1071,864,1073,1077,1078,525,1081,864,1084,1087,1088,1091,1092,1094,1095,525,1097,864,1099,1102,1103,1109,1110,1112,1113,1115],{},"The mapping's ",[459,1069,357],{}," row is where ",[459,1072,385],{},[451,1074,1075],{"href":362},[459,1076,357],{}," meet: ",[459,1079,1080],{},"Code",[459,1082,1083],{},"Public",[459,1085,1086],{},"Status",", whichever attributes the error was built or ",[459,1089,1090],{},"Define","d with, become the ",[459,1093,516],{},"'s ",[459,1096,459],{},[459,1098,945],{},[459,1100,1101],{},"status"," fields directly, with no translation layer in between. This is why declaring a failure mode once, with ",[451,1104,1106],{"href":1105},"\u002Fen\u002Ferrs\u002Fapi#errsdefine-named-failure-modes",[459,1107,1108],{},"errs.Define",", is enough to make it render correctly everywhere it's returned: the ",[459,1111,516],{}," fields are a direct read of the ",[459,1114,357],{}," attributes, not something a handler decides case by case.",[544,1117,1119],{"id":1118},"dev-mode-whose-setting-is-it","Dev mode: whose setting is it?",[447,1121,1122,1125,1126,1128,1129,1094,1134,1137,1138,1141,1142,1145,1146,1148,1149,1151,1152,1154,1155,1158],{},[459,1123,1124],{},"WithExposeInternal"," is ",[459,1127,385],{},"'s own option, but in a generated gpsystem project you never call it directly: ",[451,1130,1131],{"href":258},[459,1132,1133],{},"server.Config",[459,1135,1136],{},"ExposeInternalErrors"," field (",[459,1139,1140],{},"HTTP_EXPOSE_INTERNAL_ERRORS"," env variable) is the kit's setting, and ",[459,1143,1144],{},"server.Run"," passes it into the ",[459,1147,385],{}," writer it wires up for you. If you're using ",[459,1150,385],{}," standalone, without the kit, ",[459,1153,1020],{}," is the switch to flip yourself, guarded by whatever env variable or build tag your own project uses; just keep it ",[536,1156,1157],{},"off"," in production, the same way the kit does, so internals go to the log and Sentry, never into a response.",[544,1160,1162],{"id":1161},"the-shop-what-the-client-sees-when-stock-runs-out","The shop: what the client sees when stock runs out",[447,1164,513,1165,1168,1169,1172,1173,525,1176,1179,1180,1182,1183,1186],{},[459,1166,1167],{},"PlaceOrder"," service returns the ",[459,1170,1171],{},"ErrOutOfStock"," definition (",[459,1174,1175],{},"errs.Status(409)",[459,1177,1178],{},"errs.Public(...)","; see the declaration on the ",[451,1181,224],{"href":225}," page). By the time the ",[459,1184,1185],{},"POST \u002Fapi\u002Fv1\u002Fshop\u002Forders"," response goes out:",[483,1188,1192],{"className":1189,"code":1190,"language":1191,"meta":488,"style":488},"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",[459,1193,1194,1199,1223,1243,1259,1279,1300,1318],{"__ignoreMap":488},[492,1195,1196],{"class":494,"line":495},[492,1197,1198],{"class":502},"{\n",[492,1200,1201,1204,1206,1209,1212,1214,1218,1220],{"class":494,"line":612},[492,1202,1203],{"class":502},"  \"",[492,1205,735],{"class":601},[492,1207,1208],{"class":502},"\"",[492,1210,1211],{"class":502},":",[492,1213,503],{"class":502},[492,1215,1217],{"class":1216},"sfazB","about:blank",[492,1219,1208],{"class":502},[492,1221,1222],{"class":502},",\n",[492,1224,1225,1227,1230,1232,1234,1236,1239,1241],{"class":494,"line":659},[492,1226,1203],{"class":502},[492,1228,1229],{"class":601},"title",[492,1231,1208],{"class":502},[492,1233,1211],{"class":502},[492,1235,503],{"class":502},[492,1237,1238],{"class":1216},"Conflict",[492,1240,1208],{"class":502},[492,1242,1222],{"class":502},[492,1244,1245,1247,1249,1251,1253,1257],{"class":494,"line":666},[492,1246,1203],{"class":502},[492,1248,1101],{"class":601},[492,1250,1208],{"class":502},[492,1252,1211],{"class":502},[492,1254,1256],{"class":1255},"sbssI"," 409",[492,1258,1222],{"class":502},[492,1260,1262,1264,1266,1268,1270,1272,1275,1277],{"class":494,"line":1261},5,[492,1263,1203],{"class":502},[492,1265,945],{"class":601},[492,1267,1208],{"class":502},[492,1269,1211],{"class":502},[492,1271,503],{"class":502},[492,1273,1274],{"class":1216},"The product is out of stock.",[492,1276,1208],{"class":502},[492,1278,1222],{"class":502},[492,1280,1282,1284,1287,1289,1291,1293,1296,1298],{"class":494,"line":1281},6,[492,1283,1203],{"class":502},[492,1285,1286],{"class":601},"instance",[492,1288,1208],{"class":502},[492,1290,1211],{"class":502},[492,1292,503],{"class":502},[492,1294,1295],{"class":1216},"\u002Fapi\u002Fv1\u002Fshop\u002Forders",[492,1297,1208],{"class":502},[492,1299,1222],{"class":502},[492,1301,1303,1305,1307,1309,1311,1313,1316],{"class":494,"line":1302},7,[492,1304,1203],{"class":502},[492,1306,459],{"class":601},[492,1308,1208],{"class":502},[492,1310,1211],{"class":502},[492,1312,503],{"class":502},[492,1314,1315],{"class":1216},"shop_api_out_of_stock",[492,1317,510],{"class":502},[492,1319,1321],{"class":494,"line":1320},8,[492,1322,1323],{"class":502},"}\n",[969,1325,1326,1334,1345,1356],{},[972,1327,473,1328,1331,1332,579],{},[536,1329,1330],{},"409"," came from ",[459,1333,941],{},[972,1335,473,1336,1340,1341,1344],{},[536,1337,1338],{},[459,1339,945],{}," is the public message: the internal ",[459,1342,1343],{},"Error()"," text (query, wrap chain) never lands here,",[972,1346,473,1347,1351,1352,1355],{},[536,1348,1349],{},[459,1350,459],{}," is stable and machine-readable: the frontend can branch on it (",[459,1353,1354],{},"if (body.code === \"shop_api_out_of_stock\")","), independent of message-text changes,",[972,1357,1358,1359,1362],{},"log and Sentry: ",[536,1360,1361],{},"nothing"," (a status-mapped 4xx).",[447,1364,1365,1366,1369],{},"If the same call fails on a database error instead, the client gets a 500 with the ",[459,1367,1368],{},"shop_api_place_order_failed"," code and the generic public message, while the full chain and stack land in the log and in Sentry.",[544,1371,1373],{"id":1372},"render-and-report-in-a-single-mapping","Render and report in a single mapping",[447,1375,1376,1377,1380,1381,517,1384,517,1386,1388,1389,1392,1393,1395],{},"What the client sees (render) and what goes to the log\u002FSentry (report) lives in ",[536,1378,1379],{},"one"," central mapping: the render side is the table above (its input being ",[459,1382,1383],{},"errs.Status",[459,1385,1083],{},[459,1387,1080],{},"), the report side is the automatic 5xx logging and the ",[451,1390,1391],{"href":194},"Sentry integration",". You don't write any per-error render logic: the error mode's declaration (",[459,1394,1108],{},") carries everything the mapping works from.",[1397,1398,1399,1400,1403],"warning",{},"Don't bypass the mapping with hand-written ",[459,1401,1402],{},"w.WriteHeader(500)"," responses in handlers. Return an error instead: that keeps the response shape, the logging and the Sentry reporting consistent, and your tests see the same thing the client does.",[544,1405,1407],{"id":1406},"the-spec-side","The spec side",[447,1409,1410,1411,1414,1415,1418,1419,1421,1422,1424,1425,864,1427,1429,1430,1433,1434,1437],{},"The generated ",[459,1412,1413],{},"spec\u002Ftypespec\u002Fshared\u002Ferrors.tsp"," mirrors ",[459,1416,1417],{},"httperr.Problem"," (including ",[459,1420,520],{},"), so frontend clients generated from the OpenAPI spec get exactly this shape; see ",[451,1423,233],{"href":234},". If you extend one, extend the other. The dev-only ",[459,1426,1030],{},[459,1428,1033],{}," members are deliberately ",[536,1431,1432],{},"not"," mirrored in ",[459,1435,1436],{},"errors.tsp",": they never appear in production, so no client can build on them.",[544,1439,1441],{"id":1440},"patterns-used","Patterns used",[969,1443,1444,1456],{},[972,1445,1446,1449,1450,1452,1453,481],{},[536,1447,1448],{},"RFC 9457 Problem Details",": the ",[459,1451,516],{}," struct and the standard itself, see ",[451,1454,238],{"href":1455},"\u002Fen\u002Fconcepts\u002Fdesign-patterns#rfc-9457-problem-details",[972,1457,1458,1465,1466,481],{},[536,1459,1460,1461,1464],{},"Cascading ",[459,1462,1463],{},"errors.As"," mapping",": ",[451,1467,238],{"href":1468},"\u002Fen\u002Fconcepts\u002Fdesign-patterns#cascading-errorsas-mapping",[447,1470,1471,1472,481],{},"The official standard text: ",[451,1473,1475],{"href":453,"rel":1474},[455],"RFC 9457: Problem Details for HTTP APIs",[544,1477,1479],{"id":1478},"related-pages","Related pages",[969,1481,1482,1490,1495,1502],{},[972,1483,1484,1449,1487,1489],{},[451,1485,1486],{"href":391},"httperr: Overview",[459,1488,516],{}," shape and the quick constructors.",[972,1491,1492,1494],{},[451,1493,399],{"href":400},": the 422 shape the mapping's validation row reads.",[972,1496,1497,864,1499,1501],{},[451,1498,1045],{"href":366},[451,1500,224],{"href":225},": where the errors this page renders come from.",[972,1503,1504,1507,1508,517,1510,1512],{},[451,1505,1506],{"href":258},"The server core",": how the kit wires ",[459,1509,706],{},[459,1511,830],{}," into the generated strict server.",[1514,1515,1516],"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 .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 .spNyl, html code.shiki .spNyl{--shiki-light:#9C3EDA;--shiki-default:#C792EA;--shiki-dark:#C792EA}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 .sfazB, html code.shiki .sfazB{--shiki-light:#91B859;--shiki-default:#C3E88D;--shiki-dark:#C3E88D}html pre.shiki code .sbssI, html code.shiki .sbssI{--shiki-light:#F76D47;--shiki-default:#F78C6C;--shiki-dark:#F78C6C}",{"title":488,"searchDepth":612,"depth":612,"links":1518},[1519,1520,1521,1522,1523,1524,1525,1526,1527],{"id":546,"depth":612,"text":547},{"id":858,"depth":612,"text":859},{"id":1063,"depth":612,"text":1064},{"id":1118,"depth":612,"text":1119},{"id":1161,"depth":612,"text":1162},{"id":1372,"depth":612,"text":1373},{"id":1406,"depth":612,"text":1407},{"id":1440,"depth":612,"text":1441},{"id":1478,"depth":612,"text":1479},"The httperr package, RFC 9457 problem+json for every error, through one central mapping.","md",null,{},{"icon":397},{"title":394,"description":1528},"0kebQzRDBiDUvBQc2WLvHxcNzHLhYlmFP_zLTWuXmPQ",[1536,1538],{"title":52,"path":391,"stem":392,"description":1537,"icon":386,"children":-1},"RFC 9457 problem details for HTTP handlers.",{"title":399,"path":400,"stem":401,"description":1539,"icon":402,"children":-1},"Struct-tag-based request validation with go-playground\u002Fvalidator, run as strict middleware, with 422 problem responses.",1785445894478]