AgentStack
Browse Sign in
Browse Why AgentStack Sell Docs
Sign in
SKILL verified MIT Self-run

Error Handling

skill-jkaninda-okapi-skills-error-handling · by jkaninda

A Claude skill from jkaninda/okapi-skills.

No reviews yet
0 installs
28 views
0.0% view→install

Install

$ agentstack add skill-jkaninda-okapi-skills-error-handling

✓ scanned · ✓ verified, works with Claude Code, Cursor, and more.

Security review

✓ Passed

No issues found. Passed automated security review. · v0.1.0 How review works →

  • Prompt-injection patterns
  • Secret / credential exfiltration
  • Dangerous shell & filesystem operations
  • Untrusted network calls
  • Known-malicious package signatures

What it can access

  • Network access No
  • Filesystem access No
  • Shell / process execution No
  • Environment & secrets No
  • Dynamic code execution No

From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.

View the full security report →

Verified badge

Passed review? Show it. Paste this badge into your README, it links to the public security report.

AgentStack Verified badge Links to your public security report.
[![AgentStack Verified](https://agentstack.voostack.com/badges/verified.svg)](https://agentstack.voostack.com/security/report/skill-jkaninda-okapi-skills-error-handling)

Reliability & compatibility

Security review passed
0 installs to date
no reviews yet
1mo ago

Declared compatibility

Claude CodeClaude Desktop

Compatibility is declared by the source manifest. End-to-end runtime verification is coming, see below.

Preview Execution monitoring

We're building live execution health for every listing: tool-call success rate, median latency, uptime, and last-checked timestamps, measured, not self-reported. It isn't live yet, so we don't show numbers we can't stand behind.

How agent discovery & health will work →
Are you the author of Error Handling? Claim this listing to set pricing, connect Stripe payouts, and keep 70% of every sale.
Sign up to claim

About

Okapi Error Handling

Handlers return error. The Abort* helpers write a response through the configured ErrorHandler and return an error you propagate; the Error* helpers write a fixed JSON envelope directly, bypassing the handler. Three formats ship in the box: the default JSON envelope, a fully custom handler, and RFC 7807 Problem Details.

Aborting from a Handler

o.Post("/books", func(c *okapi.Context) error {
    book := &Book{}
    if err := c.Bind(book); err != nil {
        return c.AbortBadRequest("Invalid request body", err)
    }
    return c.Created(book)
})

Default response body (okapi.ErrorResponse):

{
  "code": 400,
  "message": "Invalid request body",
  "details": "field Name is required",
  "timestamp": "2026-08-16T21:34:17+01:00"
}

Always propagate the returned error (return c.AbortX(...)). Writing another body afterwards is a no-op — see "Write-Once Semantics" in the response/ skill.

Abort Methods

Signature: c.AbortXxx(msg string, err ...error) error. All route through the configured error handler.

4xx

| Method | Status | |--------|--------| | AbortBadRequest | 400 | | AbortUnauthorized | 401 | | AbortPaymentRequired | 402 | | AbortForbidden | 403 | | AbortNotFound | 404 | | AbortMethodNotAllowed | 405 | | AbortNotAcceptable | 406 | | AbortProxyAuthRequired | 407 | | AbortRequestTimeout | 408 | | AbortConflict | 409 | | AbortGone | 410 | | AbortLengthRequired | 411 | | AbortPreconditionFailed | 412 | | AbortRequestEntityTooLarge | 413 | | AbortRequestURITooLong | 414 | | AbortUnsupportedMediaType | 415 | | AbortRequestedRangeNotSatisfiable | 416 | | AbortExpectationFailed | 417 | | AbortTeapot | 418 | | AbortMisdirectedRequest | 421 | | AbortValidationError | 422 | | AbortLocked | 423 | | AbortFailedDependency | 424 | | AbortTooEarly | 425 | | AbortUpgradeRequired | 426 | | AbortPreconditionRequired | 428 | | AbortTooManyRequests | 429 | | AbortRequestHeaderFieldsTooLarge | 431 | | AbortUnavailableForLegalReasons | 451 |

5xx

| Method | Status | |--------|--------| | AbortInternalServerError / Abort(err) | 500 | | AbortNotImplemented | 501 | | AbortBadGateway | 502 | | AbortServiceUnavailable | 503 | | AbortGatewayTimeout | 504 | | AbortHTTPVersionNotSupported | 505 | | AbortVariantAlsoNegotiates | 506 | | AbortInsufficientStorage | 507 | | AbortLoopDetected | 508 | | AbortNotExtended | 510 | | AbortNetworkAuthenticationRequired | 511 |

Generic / special

c.Abort(err) error                                 // 500 from an error
c.AbortWithError(code int, err error) error        // any status, via the error handler
c.AbortWithStatus(code int, message string) error  // any status, default ErrorResponse shape
c.AbortWithJSON(code int, jsonObj any) error       // custom JSON payload
c.AbortWithProblemDetail(p *ProblemDetail) error   // RFC 7807 payload
c.AbortNotModified() error                         // 304, no body (per spec)
c.AbortValidationErrors(errs []ValidationError, msg ...string) error
c.AbortValidationErrorsWithProblemDetail(errs []ValidationError, msg ...string) error

Direct Error Writes (Bypass the Error Handler)

Signature: c.ErrorXxx(message any) error. These write the default JSON envelope verbatim — useful when you deliberately want a fixed shape regardless of the configured handler.

c.Error(code, message)             // basic error with status + message
c.ErrorBadRequest(err)             // 400 — accepts a string, an error, or any value
c.ErrorUnauthorized("no token")    // 401
c.ErrorForbidden(msg)              // 403
c.ErrorNotFound(msg)               // 404
c.ErrorConflict(msg)               // 409
c.ErrorUnprocessableEntity(msg)    // 422
c.ErrorTooManyRequests(msg)        // 429
c.ErrorInternalServerError(msg)    // 500
c.ErrorNotModified()               // 304, no body

The full set mirrors the Abort* table above (ErrorPaymentRequired, ErrorTeapot, ErrorLoopDetected, ErrorNetworkAuthenticationRequired, …).

Custom Error Handler

o.WithErrorHandler(func(c *okapi.Context, code int, message string, err error) error {
    details := ""
    if err != nil {
        details = err.Error()
    }
    return c.JSON(code, map[string]any{
        "success": false,
        "error": map[string]any{
            "code":    code,
            "message": message,
            "details": details,
        },
    })
})

o.WithDefaultErrorHandler() // reset to okapi.DefaultErrorHandler

Per-request override, e.g. from middleware:

func legacyErrors(c *okapi.Context) error {
    if strings.HasPrefix(c.Path(), "/v1/") {
        c.SetErrorHandler(v1ErrorHandler) // overrides the global handler for this request
    }
    return c.Next()
}

RFC 7807 Problem Details

o := okapi.Default()
o.WithSimpleProblemDetailErrorHandler() // application/problem+json, default fields
{
  "type": "about:blank",
  "title": "Bad Request",
  "status": 400,
  "detail": "field Name is required",
  "instance": "/books"
}

Full configuration:

o.WithProblemDetailErrorHandler(&okapi.ErrorHandlerConfig{
    Format:           okapi.ErrorFormatProblemJSON, // or ErrorFormatProblemXML / ErrorFormatDefault
    TypePrefix:       "https://api.example.com/errors/",
    IncludeInstance:  true,
    IncludeTimestamp: true,
    CustomFields: map[string]any{
        "api_version": "v1.0.0",
        "support_url": "https://support.example.com",
    },
})

okapi.ProblemDetailErrorHandler(cfg) returns the same handler as a plain ErrorHandler value if you want to compose it yourself.

| Format constant | Content-Type | |-----------------|--------------| | okapi.ErrorFormatDefault | application/json (standard ErrorResponse) | | okapi.ErrorFormatProblemJSON | application/problem+json | | okapi.ErrorFormatProblemXML | application/problem+xml |

Building a ProblemDetail Manually

detail := okapi.NewProblemDetail(400, "https://example.com/errors/bad-input", "Invalid input").
    WithInstance("/books/123").
    WithExtension("field", "name").
    WithTimestamp()

return c.AbortWithProblemDetail(detail)

ProblemDetail fields: Type, Title, Status, Detail, Instance, plus Extensions (flattened into the JSON object by a custom marshaller).

Structured Validation Errors

return c.AbortValidationErrors([]okapi.ValidationError{
    {Field: "email", Message: "must be a valid email", Value: input.Email},
    {Field: "age",   Message: "must be >= 18"},
}, "validation failed")
{
  "code": 422,
  "message": "validation failed",
  "timestamp": "2026-08-16T21:34:17+01:00",
  "errors": [
    {"field": "email", "message": "must be a valid email", "value": "not-an-email"},
    {"field": "age",   "message": "must be >= 18"}
  ]
}

AbortValidationErrors always uses this ValidationErrorResponse shape, even when a custom error handler is configured — it has a fixed contract. Use AbortValidationErrorsWithProblemDetail for the RFC 7807 equivalent.

Fallback Handlers

o.NoRoute(func(c *okapi.Context) error { return c.AbortNotFound("Custom 404 - Not found") })
o.NoMethod(func(c *okapi.Context) error { return c.AbortMethodNotAllowed("Custom 405") })

Errors from Standard Handlers

A net/http handler registered with HandleStd / HandleHTTP has no *Context and cannot return an error — Okapi cannot capture failures inside it. Write the error response yourself, or convert the route to a native handler.

Status Class Helpers

okapi.IsError(code) bool        // 4xx or 5xx
okapi.IsClientError(code) bool  // 4xx
okapi.IsServerError(code) bool  // 5xx

Source & license

This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.

Install and usage instructions live in the source repository linked above.

Reviews

No reviews yet, be the first.

Versions

  • v0.1.0 Imported from the upstream source.