Skip to content
Written with Claude
IMPORTANT

As you may notice, this page and pretty much the entire website were obviously created with the help of AI. I wonder how you could tell? Was it a big "Written With Claude" badge on every page? I moved it to the top now (with the help of AI of course) to make it even more obvious. There are a few blogposts that were written by me manually, the old-fashioned way, I hope there will be more in the future, and those have a similar "Human Written" badge. This project (not the website), on the other hand, is a very, very different story. It took me more than two years of painstaking and unpaid work in my own free time. A story that, hopefully, I will tell someday. But meanwhile, what would you like me to do? To create a complex documentation website with a bunch of highly technical articles with the help of AI and fake it, to give you an illusion that I also did that manually? Like the half of itnernet is doing at this point? How does that makes any sense? Is that even fair to you? Or maybe to create this website manually, the old-fashioned way, just for you? While working a paid job for a salary, most of you wouldn't even get up in the morning. Would you like me to sing you a song while we're at it? For your personal entertainment? Seriously, get a grip. Do you find this information less valuable because of the way this website was created? I give my best to fix it to keep the information as accurate as possible, and I think it is very accurate at this point. If you find some mistakes, inaccurancies or problems, there is a comment section at the bottom of every page, which I also made with the help of the AI. And I woould very much appreciate if you leave your feedback there. Look, I'm just a guy who likes SQL, that's all. If you don't approve of how this website was constructed and the use of AI tools, I suggest closing this page and never wever coming back. And good riddance. And I would ban your access if I could know how. Thank you for your attention to this matter.

Error Handling

Error handling configuration for mapping PostgreSQL errors to HTTP responses.

Overview

json
{
  "ErrorHandlingOptions": {
    "RemoveTypeUrl": false,
    "RemoveTraceId": true,
    "DefaultErrorCodePolicy": "Default",
    "TimeoutErrorMapping": {
      "StatusCode": 504,
      "Title": "Command execution timed out",
      "Details": null,
      "Type": null
    },
    "ErrorCodePolicies": [
      {
        "Name": "Default",
        "ErrorCodes": {
          "42501": {"StatusCode": 403, "Title": "Insufficient Privilege", "Details": null, "Type": null},
          "57014": {"StatusCode": 205, "Title": "Cancelled", "Details": null, "Type": null},
          "P0001": {"StatusCode": 400, "Title": null, "Details": null, "Type": null},
          "P0004": {"StatusCode": 400, "Title": null, "Details": null, "Type": null}
        }
      }
    ]
  }
}

Settings Reference

SettingTypeDefaultDescription
RemoveTypeUrlboolfalseRemove Type URL from error responses. Default Type URL points to RFC documentation based on HTTP status code.
RemoveTraceIdbooltrueRemove TraceId field from error responses. TraceId is useful for correlating logs with errors.
DefaultErrorCodePolicystring"Default"Name of the default error code policy to use.
TimeoutErrorMappingobject(see below)Error mapping for command timeout errors.
ErrorCodePoliciesarray(see below)Named policies for mapping PostgreSQL error codes to HTTP responses. Assign a policy to an endpoint using the error_code_policy annotation.

Error Mapping Object

Each error mapping has the following fields:

FieldTypeDescription
StatusCodeintHTTP status code to return.
TitlestringTitle field in response JSON. When null, the actual PostgreSQL error message is used.
DetailsstringDetails field in response JSON. When null, the PostgreSQL error code is used.
TypestringURI reference (RFC3986) identifying the problem type. When null, uses default. Set RemoveTypeUrl to true to disable.

Timeout Error Mapping

Configure the response when a command timeout occurs:

json
{
  "ErrorHandlingOptions": {
    "TimeoutErrorMapping": {
      "StatusCode": 504,
      "Title": "Command execution timed out",
      "Details": null,
      "Type": null
    }
  }
}

This maps command timeouts to HTTP 504 Gateway Timeout. Timeouts occur when a query exceeds:

  • The global NpgsqlRest.CommandTimeout setting, or
  • The per-endpoint command_timeout annotation

Error Code Policies

Define named policies for mapping PostgreSQL error codes to HTTP responses:

json
{
  "ErrorHandlingOptions": {
    "DefaultErrorCodePolicy": "Default",
    "ErrorCodePolicies": [
      {
        "Name": "Default",
        "ErrorCodes": {
          "42501": {"StatusCode": 403, "Title": "Insufficient Privilege", "Details": null, "Type": null},
          "57014": {"StatusCode": 205, "Title": "Cancelled", "Details": null, "Type": null},
          "P0001": {"StatusCode": 400, "Title": null, "Details": null, "Type": null},
          "P0004": {"StatusCode": 400, "Title": null, "Details": null, "Type": null}
        }
      }
    ]
  }
}

Default Error Code Mappings

PostgreSQL CodeNameHTTP StatusDescription
42501insufficient_privilege403 ForbiddenUser lacks required permissions
57014query_canceled205 Reset ContentQuery was cancelled
P0001raise_exception400 Bad RequestExplicit RAISE EXCEPTION in function
P0004assert_failure400 Bad RequestAssert statement failed

See PostgreSQL Error Codes for the complete list.

Response Fields

Type URL

When RemoveTypeUrl is false (default), error responses include a Type URL pointing to RFC documentation:

json
{
  "type": "https://tools.ietf.org/html/rfc7231#section-6.5.1",
  "title": "Bad Request",
  "status": 400
}

TraceId

When RemoveTraceId is false, error responses include a TraceId for log correlation:

json
{
  "type": "https://tools.ietf.org/html/rfc7231#section-6.5.1",
  "title": "Bad Request",
  "status": 400,
  "traceId": "00-abc123..."
}

Example Configuration

Production configuration with custom error mappings:

json
{
  "ErrorHandlingOptions": {
    "RemoveTypeUrl": false,
    "RemoveTraceId": true,
    "DefaultErrorCodePolicy": "Default",
    "TimeoutErrorMapping": {
      "StatusCode": 504,
      "Title": "Request timed out",
      "Details": "The database operation took too long to complete.",
      "Type": null
    },
    "ErrorCodePolicies": [
      {
        "Name": "Default",
        "ErrorCodes": {
          "42501": {"StatusCode": 403, "Title": "Insufficient Privilege", "Details": null, "Type": null},
          "57014": {"StatusCode": 205, "Title": "Cancelled", "Details": null, "Type": null},
          "P0001": {"StatusCode": 400, "Title": null, "Details": null, "Type": null},
          "P0004": {"StatusCode": 400, "Title": null, "Details": null, "Type": null},
          "23505": {"StatusCode": 409, "Title": "Conflict", "Details": "A record with this key already exists.", "Type": null},
          "23503": {"StatusCode": 400, "Title": "Invalid Reference", "Details": "Referenced record does not exist.", "Type": null}
        }
      }
    ]
  }
}

Development configuration with TraceId for debugging:

json
{
  "ErrorHandlingOptions": {
    "RemoveTypeUrl": false,
    "RemoveTraceId": false,
    "DefaultErrorCodePolicy": "Default"
  }
}

Next Steps

Comments

Released under the MIT License.