API Contracts & ErrorsESSENTIAL7 min deep dive

Error Messages & Standardized Error Envelopes

#RFC 7807#Problem Details#Error Envelopes#Security Leaks#HTTP Status

The 3-Line Engineering Rule

1. THE RULE

Return consistent, structured error envelopes (RFC 7807 Problem Details); never leak raw stack traces or SQL exceptions to API clients.

2. WHY IT MATTERS

Raw stack traces expose internal class names, database schemas, and library versions to attackers, while inconsistent error shapes break frontend error handling.

3. PRODUCTION FIX

Standardize on RFC 7807: include `type`, `title`, `status`, `detail`, `instance`, and an opaque `error_id` (trace ID) so users can report issues without seeing raw code internals.

Architectural Blueprint & Sequence

Hover over nodes to inspect state transitions
RFC 7807 ERROR ENVELOPESCRIBBLE BLUEPRINT
Standardized error payload protecting internal stack traces while providing client clarity
#1
Security Leak!

❌ RAW EXCEPTION LEAK

HTTP 500: PSQLException: relation 'users' does not exist at org.postgresql.core...

#2
Clean & Actionable

✅ RFC 7807 PROBLEM DETAILS

{ status: 422, title: 'Unprocessable Entity', detail: 'Insufficient stock', error_id: 'err_8f9a' }

#3

Customer Support / Triage

Look up error_id in Loki/Elasticsearch

Execution Sequence & Transitions
❌ RAW EXCEPTION LEAK✅ RFC 7807 PROBLEM DETAILS[sanitize via @ControllerAdvice]
✅ RFC 7807 PROBLEM DETAILSCustomer Support / Triage[quote error_id]

Key Engineering Takeaways

  • Adopt RFC 7807 'Problem Details for HTTP APIs' across all services.
  • Always attach an `error_id` / `trace_id` so frontend users can quote it to customer support.
  • Never leak SQL syntax errors, database passwords, or full Java stack traces to API clients.
  • Distinguish client errors (4xx - invalid input) from internal system defects (5xx - server crash).

The Problem & Production Reality

When an API call fails, the client needs to know two things: What went wrong? How can I fix it? Returning inconsistent string messages like `"Something broke"` on one endpoint and an HTML stack trace on another creates a frustrating developer experience and leaks attack vectors.

Anti-Pattern: Default Framework Error Pages & Leaked Stack Traces

Allowing uncaught exceptions to bubble up to Tomcat or Express, returning raw database traces to the browser.

ANTI-PATTERN EXAMPLE (HTTP)
// ❌ ANTI-PATTERN: Leaks database table names and credentials
HTTP/1.1 500 Internal Server Error
Content-Type: text/plain

org.postgresql.util.PSQLException: ERROR: duplicate key value violates unique constraint "users_email_key"
  Detail: Key (email)=(john@example.com) already exists.
  at org.hibernate.exception.internal.SQLStateConverter...

Production Pattern: RFC 7807 ProblemDetail Global Handler

Use Spring's native `ProblemDetail` or custom RFC 7807 envelope with sanitized client messages and an opaque trace ID.

PRODUCTION-READY CODE (JAVA)
// ✅ PRODUCTION PATTERN: RFC 7807 Global Exception Handling
@RestControllerAdvice
public class GlobalExceptionHandler {

    private static final Logger log = LoggerFactory.getLogger(GlobalExceptionHandler.class);

    @ExceptionHandler(InsufficientInventoryException.class)
    public ProblemDetail handleInventoryError(InsufficientInventoryException ex, HttpServletRequest req) {
        String errorId = MDC.get("traceId");
        
        ProblemDetail problem = ProblemDetail.forStatusAndDetail(
            HttpStatus.UNPROCESSABLE_ENTITY, 
            ex.getMessage() // Safe domain message: "Only 2 items remain in stock."
        );
        problem.setTitle("Inventory Shortage");
        problem.setType(URI.create("https://beingsde.in/errors/insufficient-inventory"));
        problem.setInstance(URI.create(req.getRequestURI()));
        problem.setProperty("error_id", errorId);
        problem.setProperty("available_quantity", ex.getAvailableQuantity());
        problem.setProperty("timestamp", Instant.now());
        
        return problem;
    }

    @ExceptionHandler(Exception.class)
    public ProblemDetail handleUnexpectedCrash(Exception ex, HttpServletRequest req) {
        String errorId = UUID.randomUUID().toString().substring(0, 8);
        log.error("Unhandled internal server crash: error_id={}", errorId, ex);
        
        // NEVER leak ex.getMessage() for unexpected 500s!
        ProblemDetail problem = ProblemDetail.forStatusAndDetail(
            HttpStatus.INTERNAL_SERVER_ERROR,
            "An unexpected server error occurred. Please quote error_id to support."
        );
        problem.setTitle("Internal Server Error");
        problem.setProperty("error_id", errorId);
        return problem;
    }
}

Trade-off Analysis & Staff Recommendations

AspectPros / StrengthsCons / HazardsStaff Recommendation
Custom JSON vs RFC 7807 Problem DetailsRFC 7807 is an open IETF internet standard natively supported by modern frameworks.Requires migrating legacy frontend parsers to expect the standard schema.Adopt RFC 7807 for all new microservices; it is standard in Spring Boot 3+ and .NET 7+.
Developer Details in Staging vs ProdShowing stack traces in local dev speeds up debugging.Accidentally leaving dev mode on in production causes security breaches.Completely disable stack trace inclusion in HTTP responses at the build/profile level.

PR Code Review Checklist (Click to verify)