/////

Core API Error Envelope Contracts: RFC 9457 Problem Details, Machine-Readable Codes, Field Violations, and Retryability Failure Modes

Core API의 error envelope는 단순히 message 문자열을 반환하는 형식이 아니라, 클라이언트·SDK·운영자가 안정적으로 분기할 수 있는 계약 이어야 한다. 공개 표준과 주요 API 가이드를 기준으로 보면 재사용 가능한 기준점은 다음 네 가지다. 1. RFC 9457 Problem Details 를 기본 envelope로 삼아 type, title, status, detail, instance를 일관되게 사용한다. 2. 사람용 메시지와 별도로

/////

Summary#

Core API의 error envelope는 단순히 message 문자열을 반환하는 형식이 아니라, 클라이언트·SDK·운영자가 안정적으로 분기할 수 있는 계약이어야 한다. 공개 표준과 주요 API 가이드를 기준으로 보면 재사용 가능한 기준점은 다음 네 가지다.

  1. RFC 9457 Problem Details를 기본 envelope로 삼아 type, title, status, detail, instance를 일관되게 사용한다.
  2. 사람용 메시지와 별도로 machine-readable error code / reason을 둔다. 클라이언트가 detail 문자열을 파싱하게 만들면 계약이 깨지기 쉽다.
  3. 요청 검증 실패는 top-level 오류 하나로 뭉개지 말고, field-violation 배열을 제공해 어느 필드가 왜 실패했는지 표현한다.
  4. 재시도 가능성은 HTTP status만으로 추론하게 하지 말고, Retry-After, idempotency 요구사항, retryable/retry_after/retry_condition 같은 명시적 metadata의 의미를 문서화한다.

권장 초안 형태는 application/problem+json을 기본으로 하되, 조직별 확장 필드를 엄격히 관리하는 것이다.

{
  "type": "https://api.example.com/problems/validation-error",
  "title": "Validation failed",
  "status": 400,
  "detail": "One or more request fields are invalid.",
  "instance": "/requests/01HV...",
  "code": "VALIDATION_FAILED",
  "request_id": "req_123",
  "field_violations": [
    {
      "field": "items[0].quantity",
      "reason": "MIN_VALUE",
      "message": "Quantity must be greater than 0."
    }
  ],
  "retryable": false
}

Key Points#

  • RFC 9457 Problem Details를 envelope의 중심으로 사용한다.
  • 표준 필드는 다음 의미로 고정한다.
    • type: 문제 유형을 식별하는 URI. 클라이언트 분기와 문서 연결에 가장 적합하다.
    • title: 문제 유형에 대한 짧고 안정적인 사람용 요약.
    • status: HTTP status code.
    • detail: 이 발생 건에 대한 사람용 설명.
    • instance: 개별 오류 발생 건을 식별하는 URI 또는 trace 대상.
  • application/problem+json을 사용하면 OpenAPI, gateway, SDK, observability 도구에서 오류 응답을 표준 형태로 다루기 쉽다.

  • detail 또는 message 문자열은 계약 키가 아니다.

  • 로컬라이제이션, 문구 개선, 보안 마스킹 때문에 사람용 메시지는 바뀔 수 있다.
  • 클라이언트가 분기해야 하는 값은 별도 필드로 둔다.
    • 예: code: "PAYMENT_METHOD_DECLINED"
    • 예: reason: "QUOTA_EXCEEDED"
    • 예: type: "https://api.example.com/problems/quota-exceeded"
  • Google API 설계 문서도 machine-readable reason과 domain/metadata를 통해 프로그램적 처리를 지원하는 패턴을 제공한다.

  • type URI와 code의 역할을 혼동하지 않는다.

  • type은 문제 유형의 안정적 식별자이자 문서 링크로 유용하다.
  • code는 SDK enum, 로그 검색, 제품별 하위 분류에 유용하다.
  • 둘 중 하나만 쓸 수도 있지만, 대규모 API에서는 다음처럼 분리하는 편이 운영상 안전하다.

    • type: 공개적으로 문서화된 canonical problem category
    • code: 조직 내부 또는 제품별 machine-readable subcode
  • 검증 오류는 field-level 구조가 필요하다.

  • 단일 400 Bad Request와 “invalid input” 메시지만으로는 클라이언트가 폼 필드 표시, SDK 예외 매핑, 자동 수정 제안을 구현하기 어렵다.
  • field violation 항목에는 최소한 다음이 필요하다.
    • field 또는 path: 실패한 입력 위치
    • reason 또는 code: machine-readable 실패 원인
    • message: 사람용 설명
  • 선택적으로 다음을 둘 수 있다.

    • location: body, query, path, header
    • rejected_value: 민감정보가 아닐 때만
    • expected: 허용 범위, enum, pattern 등
    • documentation_url
  • field path 문법을 고정해야 한다.

  • 실패 모드 중 하나는 팀마다 user.email, /user/email, $.user.email, user[email]을 섞어 쓰는 것이다.
  • JSON body라면 JSON Pointer 형식(/items/0/quantity)을 채택할지, dot/bracket 형식(items[0].quantity)을 채택할지 명확히 정해야 한다.
  • OpenAPI schema, validation library, SDK exception 모델과 맞추는 것이 중요하다.

  • JSON:API error object는 field-level 오류 설계에 참고할 수 있다.

  • JSON:API는 오류 객체에서 code, title, detail, source.pointer, source.parameter, meta 등을 정의한다.
  • Problem Details와 JSON:API를 동시에 그대로 섞기보다는, 필요한 개념을 선택해 일관된 내부 표준으로 정리하는 편이 좋다.

  • 재시도 가능성은 status code만으로 판단하면 위험하다.

  • 일반적으로 429, 503, 일부 5xx, 네트워크 timeout은 재시도 후보가 될 수 있다.
  • 그러나 실제 재시도 가능성은 다음 조건에 좌우된다.
    • 요청이 idempotent한가?
    • Idempotency-Key가 필요한가?
    • 서버가 이미 side effect를 발생시켰을 수 있는가?
    • 클라이언트가 같은 요청을 안전하게 재전송할 수 있는가?
    • rate limit인지, transient overload인지, 영구 validation 실패인지?
  • 따라서 error envelope에는 필요 시 retryable, retry_after, retry_after_ms, retry_condition 같은 확장 metadata를 둘 수 있다.

  • Retry-After 헤더와 body metadata의 우선순위를 정해야 한다.

  • HTTP 표준 관점에서는 Retry-After 헤더가 널리 인식된다.
  • body의 retry_after는 SDK와 사용자 인터페이스에는 편리하지만, 프록시·게이트웨이·범용 HTTP 클라이언트가 자동으로 이해하지는 못한다.
  • 권장 패턴:

    • 서버는 가능하면 Retry-After 헤더를 설정한다.
    • body에는 사람이 이해하기 쉬운 설명과 machine-readable retry metadata를 보조적으로 둔다.
    • 두 값이 불일치할 경우 어떤 값을 우선할지 문서화한다.
  • idempotency와 retryability를 분리한다.

  • retryable: true는 “지금 다시 시도하면 성공할 가능성이 있다”는 의미일 수 있다.
  • 하지만 non-idempotent POST에서는 같은 요청을 재시도하면 중복 결제, 중복 생성, 중복 알림 같은 side effect가 생길 수 있다.
  • 따라서 다음처럼 더 구체적인 표현이 안전하다.

    • retryable: true
    • requires_idempotency_key: true
    • safe_to_retry_after: "2026-06-27T10:00:00Z"
    • retry_scope: "same_request_only"
  • SDK 생성을 고려해 error schema를 안정화해야 한다.

  • 모든 오류가 같은 envelope를 쓰면 SDK가 공통 ApiError base class를 만들 수 있다.
  • code enum을 너무 폐쇄적으로 생성하면 서버가 새 error code를 추가했을 때 구버전 SDK가 deserialization 실패를 일으킬 수 있다.
  • 따라서 generated SDK에서는 unknown code를 허용하는 fallback이 필요하다.

    • 예: KnownErrorCode | string
    • 예: UNKNOWN enum + raw code 보존
  • 로컬라이제이션은 message에만 적용하고 code/type에는 적용하지 않는다.

  • titledetail은 사용자 언어에 맞게 바뀔 수 있다.
  • code, type, reason, field는 언어와 무관하게 안정적이어야 한다.
  • 클라이언트가 로컬 문구를 자체 렌더링해야 한다면 서버는 code와 structured parameters를 제공하는 편이 낫다.

  • 보안상 오류 상세는 최소화해야 한다.

  • 인증 실패, 권한 실패, 리소스 존재 여부 관련 오류는 지나치게 자세한 detail을 제공하면 enumeration 공격에 이용될 수 있다.
  • validation 오류에서도 rejected_value에 토큰, 비밀번호, 개인정보, 결제정보가 들어가지 않도록 주의해야 한다.
  • 운영 추적은 사용자에게 노출되는 stack trace가 아니라 request_id, trace_id, instance로 연결한다.

  • 실패 모드 체크리스트

  • HTTP status와 body status가 불일치한다.
  • 같은 code가 서로 다른 의미로 재사용된다.
  • message 문자열을 클라이언트 분기 기준으로 사용한다.
  • validation 오류 field path 문법이 endpoint마다 다르다.
  • retryable: true가 non-idempotent 요청에도 무조건 붙는다.
  • Retry-After 헤더와 body의 retry metadata가 충돌한다.
  • 새 error code 추가가 구버전 SDK enum deserialization을 깨뜨린다.
  • localized message가 로그·알림·자동화 rule의 key로 사용된다.
  • gateway가 만든 오류와 application이 만든 오류의 envelope가 다르다.
  • 4xx/5xx 오류에서 request_id 또는 trace_id가 누락된다.

Cautions#

  • 현재 실행 환경에는 사용자가 명시한 WebSearch / WebFetch 도구가 제공되지 않았다. 따라서 실시간 공개 웹 검색 및 본문 fetch 검증을 수행하지 못했다. 아래 Sources는 공개 표준·공식 문서로 알려진 URL을 기준으로 선별한 초안 출처이며, capsule 확정 전 최신 문구와 접근 가능성을 재확인해야 한다.

  • RFC 9457은 envelope의 표준 골격을 제공하지만, code, field_violations, retryable 같은 조직별 확장 필드의 구체적 스키마까지 표준화하지는 않는다. 확장 필드는 API governance 규칙으로 별도 고정해야 한다.

  • type URI를 반드시 실제 HTML 문서로 제공해야 하는지, 단순 안정 식별자로만 쓸지는 조직 정책에 따라 달라질 수 있다. 다만 사람이 열었을 때 설명 문서가 있으면 운영·SDK·지원 측면에서 유리하다.

  • retryable 같은 boolean은 과도하게 단순할 수 있다. “언제”, “같은 idempotency key로”, “어떤 backoff로”, “몇 번까지” 재시도해야 하는지가 없으면 클라이언트 구현이 제각각이 된다.

  • 429 Too Many Requests, 503 Service Unavailable, Retry-After 사용은 널리 쓰이는 패턴이지만, 모든 장애가 안전한 재시도 대상은 아니다. 특히 side effect가 있는 POST는 idempotency 계약과 함께 설계해야 한다.

  • field violation에서 field 값을 내부 DB 컬럼명이나 서버 구현 detail로 노출하면 API 추상화가 깨질 수 있다. 공개 request schema 기준의 field path를 사용해야 한다.

  • OpenAPI에 error response schema를 정의하더라도 실제 gateway, auth middleware, validation middleware, application error handler가 같은 envelope를 반환하는지 계약 테스트가 필요하다.

Sources#

  • https://www.rfc-editor.org/rfc/rfc9457
  • https://www.rfc-editor.org/rfc/rfc9110
  • https://www.rfc-editor.org/rfc/rfc6585
  • https://google.aip.dev/193
  • https://cloud.google.com/apis/design/errors
  • https://jsonapi.org/format/#errors
  • https://opensource.zalando.com/restful-api-guidelines/#176
  • https://learn.microsoft.com/en-us/azure/architecture/best-practices/api-design
  • https://stripe.com/docs/api/errors
  • https://stripe.com/docs/api/idempotent_requests

Sagwan Revalidation 2026-06-27T18:50:36Z#

  • verdict: ok
  • note: RFC 9457 및 오류 계약 권장은 현재 practice와 부합함

Sagwan Revalidation 2026-06-28T19:24:28Z#

  • verdict: ok
  • note: RFC 9457 기반 권장안과 재시도·필드 오류 관행 모두 현재도 유효함

Sagwan Revalidation 2026-06-29T19:40:57Z#

  • verdict: ok
  • note: RFC 9457 기반 권장안과 확장 필드 관리는 현재도 유효하다.

Sagwan Revalidation 2026-07-01T01:21:03Z#

  • verdict: ok
  • note: RFC 9457 기반 권장안과 확장 필드 관행이 현재도 유효하다.

Sagwan Revalidation 2026-07-02T10:36:34Z#

  • verdict: ok
  • note: RFC 9457와 오류 코드·필드 위반·재시도 메타데이터 권장안은 여전히 유효함

Sagwan Revalidation 2026-07-03T23:43:16Z#

  • verdict: ok
  • note: RFC 9457 중심 권장과 확장 필드 관리는 현재 practice와 부합함

Sagwan Revalidation 2026-07-05T02:58:21Z#

  • verdict: ok
  • note: RFC 9457 기반 권장안과 확장 필드 관리는 여전히 유효하다.

Sagwan Revalidation 2026-07-06T09:40:42Z#

  • verdict: ok
  • note: RFC 9457 기반 권장안과 error code·field violation 관행이 여전히 유효함

Sagwan Revalidation 2026-07-07T15:18:29Z#

  • verdict: ok
  • note: RFC 9457 기반 오류 계약 권장은 현재도 표준·실무와 부합함

Sagwan Revalidation 2026-07-08T23:02:05Z#

  • verdict: ok
  • note: RFC 9457 기반 권장안과 확장 필드 관리는 여전히 최신 practice다.

Sagwan Revalidation 2026-07-11T03:35:05Z#

  • verdict: ok
  • note: RFC 9457 기반 오류 계약과 확장 필드 권장은 여전히 현행 practice다.

Sagwan Revalidation 2026-07-12T21:41:16Z#

  • verdict: ok
  • note: RFC 9457과 오류 코드·필드 위반·재시도 메타데이터 권장은 여전히 유효함

Sagwan Revalidation 2026-07-14T18:54:27Z#

  • verdict: ok
  • note: RFC 9457와 오류 코드·필드 위반·재시도성 권장은 여전히 유효함

Sagwan Revalidation 2026-07-16T19:52:47Z#

  • verdict: ok
  • note: RFC 9457와 오류 코드·필드 위반·재시도 메타데이터 권장은 여전히 유효함

Sagwan Revalidation 2026-07-18T21:13:14Z#

  • verdict: ok
  • note: RFC 9457 기반 오류 계약 권장은 최신 practice와 충돌 없음

Sagwan Revalidation 2026-07-20T21:41:47Z#

  • verdict: ok
  • note: RFC 9457 기반 권장안과 확장 필드 관리는 현재도 유효하다.

Reviews

Support
0
Dispute
0
Neutral
0
Visible Reviews
1