An API error boundary converts failures into a declared response shape while retaining the intended HTTP status.
Flask error responses: preserve status without exposing internal exception text
Operation contract
The local application converts HTTP exceptions into JSON with their numeric status and a fixed public message. Unexpected application failures return a separate fixed 500 message rather than copying exception text. Local test-client requests cover a missing path, wrong method, oversized JSON and an internal failure. The request-size limit is checked when the endpoint reads its body.
Failure and ownership boundary
This response fixture does not configure production logging, trace IDs, alerting or a proxy body limit. An error handler must not translate every HTTP exception into status 200 or expose diagnostic strings to clients. Frontend retries also need a policy for which failures are transient. Python logging: allowlist fields before they reach a handler, Flask JSON API: reject unknown fields, booleans and oversized bodies and Spring MVC ProblemDetail: stable errors without leaking internals cover connected choices.
Tested environment
Dependency check: this program was executed on CPython 3.14.6 with Flask==3.1.3. Install these versions in a separate virtual environment. The download includes the recorded environment snapshot; no third-party package is part of the website runtime.
Working program
from flask import Flask, jsonify, request
from werkzeug.exceptions import HTTPException
application = Flask(__name__)
application.config["MAX_CONTENT_LENGTH"] = 64
@application.errorhandler(HTTPException)
def http_failure(failure):
return jsonify(status=failure.code, error="request rejected"), failure.code
@application.errorhandler(Exception)
def internal_failure(failure):
return jsonify(status=500, error="internal failure"), 500
@application.post("/receipts")
def create_receipt():
request.get_json()
return jsonify(accepted=True), 201
@application.get("/owned-failure")
def owned_failure():
raise RuntimeError("owned diagnostic not for the response")
client = application.test_client()
print("missing:", client.get("/missing").status_code)
print("method:", client.get("/receipts").status_code)
print("oversized:", client.post("/receipts", data='"' + 'x' * 100 + '"', content_type="application/json").status_code)
failure = client.get("/owned-failure")
print("internal:", failure.status_code, failure.get_json()["error"])
print("diagnostic exposed:", b"owned diagnostic" in failure.data)Output
missing: 404
method: 405
oversized: 413
internal: 500 internal failure
diagnostic exposed: FalseCosts and limits
The fixtures have small bounded bodies and no network listener. Error serialization adds bounded response work here; logging/diagnostics can have their own I/O and privacy costs. The broad application handler does not make arbitrary failures safe to retry.
Common Mistakes
- Keep the intended failure status rather than always returning 200.
- Public error text must not copy arbitrary internal exception messages.
Connected lessons
Python logging: allowlist fields before they reach a handler, Flask JSON API: reject unknown fields, booleans and oversized bodies, Spring MVC ProblemDetail: stable errors without leaking internals.
