개발자 문서
개발자 문서

오류 코드

실패한 요청은 error 객체로 답합니다. 코드로 분기하고, 재시도 여부는 응답이 알려 줍니다.

오류 응답에는 error 객체가 있습니다. code 로 프로그램이 분기하고, message 는 사람이 읽는 설명이라 로그와 서비스문의에 씁니다.

retryable 이 true 면 같은 요청을 다시 보낼 의미가 있고, false 면 요청이나 설정을 고쳐야 합니다. 같은 code 안에서 상황을 더 가르고 싶을 때만 선택 필드 reason 을 봅니다.

사유 칸이 없는 응답 (HTTP 429)

json
{
  "error": {
    "code": "POLICY_QUOTA_EXCEEDED",
    "message": "데모 환경의 오늘 쓸 수 있는 사용 토큰을 모두 썼습니다. 9월 11일 0시(한국 시간)에 다시 채워지며, 기다리는 데 비용은 들지 않습니다. 정식 환경은 이 한도를 세지 않으며 PRO 또는 멀티계정 요금제에서 쓸 수 있습니다.",
    "retryable": false,
    "provider_error_ref": null,
    "trace_id": "trc_5f0c2a9e8d7b4c1f9a3e6b2d4c8f1a07"
  }
}

reason 이 붙는 응답 (HTTP 403)

json
{
  "error": {
    "code": "POLICY_ENV_FORBIDDEN",
    "message": "데모 환경은 사용 신청이 승인된 뒤 쓸 수 있습니다. 콘솔 프로필의 환경 메뉴에서 신청해 주세요.",
    "retryable": false,
    "provider_error_ref": null,
    "trace_id": "trc_5f0c2a9e8d7b4c1f9a3e6b2d4c8f1a07",
    "reason": "demo_access_not_approved"
  }
}

오류 본문의 모양

본문 모양이럴 때error 를 읽는 곳
{"error": {...}}오류 응답의 기본 모양입니다. 인증, 권한, 요금제, 환경, 한도 검사에서 거절된 요청과 작업 제출과 조회 오류가 모두 이 모양이고, 위 예시가 그렇습니다. Idempotency-Key 를 빠뜨렸을 때의 IDEMPOTENCY_KEY_REQUIRED 나 없는 작업을 조회할 때의 JOB_NOT_FOUND 도 같습니다.error.code
{"error": {..., "fields": [...]}} (HTTP 422)요청 본문의 필드 형식이 틀렸을 때입니다(필수 필드 빠짐, 문자열이어야 할 값이 객체나 숫자). error.code 는 VALIDATION_INVALID_FIELD 이고, error.fields 배열의 각 항목이 어느 필드가 왜 틀렸는지 알려 줍니다. 보낸 값은 되돌려 주지 않습니다.error.code, 필드별 안내는 error.fields 항목의 loc(위치)와 msg(이유)
{"detail": "문자열"}없는 주소의 404 처럼 오류 코드가 없는 응답입니다. error 는 없습니다.HTTP 상태와 detail 문장을 그대로 기록

코드에서는 본문 최상위 error 를 읽으면 됩니다. error 가 없으면(없는 주소의 404 등) HTTP 상태와 detail 문장을 그대로 기록합니다.

응답 필드

필드설명
code아래 표에 있는 값 중 하나입니다. 분기는 이 값으로 합니다.
message사람이 읽는 문장입니다. 키·권한·요금제·환경·한도·동의 관련 거절은 바로 읽을 수 있는 한국어로 오고, 그 밖의 오류는 원인을 적은 기술 문구(영문일 수 있음)로 올 수 있습니다. 문구는 바뀔 수 있어 분기에 쓰지 않습니다. 최종 사용자 화면에는 code 에 맞춘 자체 문구를 보여 주세요.
retryable같은 요청을 다시 보낼 의미가 있는지 알려 줍니다. 이 값이 최종입니다 — 되돌릴 수 없는 작업(발행·신고·신청)의 실패는 아래 코드별 표와 달리 항상 false 로 옵니다.
provider_error_ref실패한 지점을 가리키는 추적 값입니다. 보통 상품이름.원인 꼴이고(예: hometax.read_timeout), 없으면 null 입니다.
trace_id이 요청의 추적 아이디입니다. 서비스문의에 남길 때 그대로 알려 주세요.
fields선택. HTTP 422 요청 본문 검증 오류에만 있습니다. 어느 필드가 왜 틀렸는지 알려 주는 목록이고 항목마다 loc(위치), msg(이유), type(종류)이 있습니다. 보낸 값은 되돌려 주지 않습니다.
reason선택. 같은 code 가 여러 상황을 뜻할 때 상황을 가르는 기계용 값입니다. 화면에 보여 주는 값이 아니고, 해당하는 오류에만 있으며 없으면 칸 자체가 없습니다. code 로 먼저 분기하고 더 세분해야 할 때만 보세요. MCP 는 JSON-RPC 오류의 error.data.reason 에 같은 값이 실립니다.

reason 값

코드reason언제
POLICY_ENV_FORBIDDENkey_env_not_allowed요청한 환경이 이 키에 없습니다. 정식은 유료 요금제를, 데모는 사용 신청 승인을 따라 기존 키에 더해지므로 키를 다시 발급하지 않아도 됩니다.
POLICY_ENV_FORBIDDENdemo_access_not_approved데모(real_test) 사용 신청이 승인되기 전에 호출했습니다. 콘솔 프로필의 환경 메뉴에서 신청합니다.
POLICY_ENV_FORBIDDENorganization_required데모 환경 요청에는 조직 정보가 필요한데 조직에 속하지 않은 계정으로 호출했습니다.
POLICY_PAID_REQUIREDproduction_requires_paid유료 요금제를 이용 중이 아닌데 정식(production) 환경을 호출했습니다. 스탠다드는 데모 환경에서 그대로 쓸 수 있습니다.
POLICY_PAID_REQUIREDsubscription_paused결제가 일시 중지되어 요청을 처리할 수 없습니다. 콘솔 결제 관리에서 결제 상태를 확인합니다.
POLICY_PAID_REQUIREDinvalid_subscription_status요금제 상태를 확인하지 못했습니다. 잠시 뒤 다시 시도하고, 계속되면 서비스문의로 알려 주세요.
AUTHZ_FORBIDDENoauth_scope_missingMCP 연결(OAuth)에 도구를 실행할 권한이 없습니다. AI 클라이언트에서 연결을 다시 승인합니다.
AUTHZ_FORBIDDENoauth_token_mcp_onlyAI 앱 연결(MCP)용으로 받은 OAuth 토큰을 서버 연동(REST)에 썼습니다. 다시 승인해도 풀리지 않으며, 서버 연동에는 콘솔에서 발급한 API 키(HTTP Basic)를 씁니다.
POLICY_PROVIDER_FORBIDDENavailable_in_other_env이 요금제에 있는 상품인데 요청한 환경에서는 쓸 수 없습니다. 요금제를 바꿀 필요 없이, 메시지가 알려 주는 환경(샌드박스 sandbox, 데모 real_test, 정식 production 중 하나)의 X-Env-Scope 값으로 바꿔 다시 보냅니다.
POLICY_PROVIDER_FORBIDDENnot_sold_yet아직 제공하지 않는 기능을 호출했습니다. 어느 요금제에도 아직 없는 기능입니다. 제공 계획은 서비스문의로 문의합니다.
POLICY_PROVIDER_FORBIDDENsale_ended제공이 종료된 기능을 호출했습니다. 팔다가 내린 기능입니다. 대신 쓸 수 있는 기능이 있는지 서비스문의로 문의합니다.
RESOURCE_CONFLICTmaterial_replacement_not_confirmed이미 등록된 계정과 같은 아이디인데 비밀번호가 다릅니다. 바꾸려는 것이 맞다면 요청 본문에 confirm 을 true 로 넣어 다시 보냅니다. 그대로 진행하면 저장된 비밀번호가 바뀌고 그 연동으로 열어 둔 기관 세션이 모두 끊어집니다.

표에 없는 reason 이 오면 무시하고 code 만으로 처리합니다 — 값이 더해질 수 있습니다. 콘솔 화면이 쓰는 값(조직·멤버·초대·환경 신청)은 개발자 API 로 오지 않아 싣지 않았습니다.

이 문서에는 아직 판매하지 않는 기능도 미리 실려 있습니다. 그런 기능을 부르면 POLICY_PROVIDER_FORBIDDEN 에 reason not_sold_yet 로 거절되고, 팔다가 내린 기능은 sale_ended 로 거절됩니다. 둘 다 요금제를 바꾸거나 추가 구매해도 풀리지 않습니다 - 살 수 있는 요금제가 없는 기능이라서입니다. 이 단락은 문서의 설명이고 서버가 보내는 문장이 아닙니다. 서버 문장은 응답의 message 를 그대로 읽습니다.

자주 만나는 오류

코드HTTP재시도할 일
AUTH_CREDENTIAL_MISSING401무의미Authorization 헤더를 넣습니다.
AUTH_CREDENTIAL_INVALID401무의미client_id 와 client_secret, Base64 인코딩을 확인하고, 폐기된 키라면 콘솔에서 새 키로 바꿉니다.
POLICY_ENV_FORBIDDEN403무의미X-Env-Scope 값과 키가 쓸 수 있는 환경을 맞춥니다.
POLICY_PAID_REQUIRED402무의미정식 환경은 유료 플랜을 이용 중일 때만 호출할 수 있습니다.
POLICY_QUOTA_EXCEEDED429무의미데모 일일 한도입니다. 다음 날 0시(KST)에 초기화됩니다.
POLICY_RATE_LIMIT_EXCEEDED429가능잠시 기다렸다 다시 호출합니다.
IDEMPOTENCY_KEY_REQUIRED400무의미Idempotency-Key 헤더를 넣습니다.
IDEMPOTENCY_KEY_CONFLICT409무의미내용이 다른 요청이므로 새 키로 보냅니다.
VALIDATION_INVALID_FIELD400, 422무의미본문·헤더 형식과 필드 이름 규칙을 확인합니다. HTTP 422 이면 error.fields 가 틀린 필드를 알려 줍니다. 작업이 접수(202)된 뒤 이 코드로 끝나고 provider_error_ref 가 missing_account_link_id 로 끝나면, 본문이 아니라 등록한 자격증명이 없는 것입니다.
RESOURCE_NOT_FOUND404무의미account_link_id 가 이 키를 만든 사용자가 등록한 것이고 아직 사용 중인지 확인합니다.
JOB_NOT_FOUND404무의미작업 아이디와 X-Env-Scope 가 제출할 때와 같은지 확인합니다.
JOB_INVALID_TRANSITION409무의미작업이 SUCCEEDED 가 된 뒤에 결과를 조회합니다.
PROVIDER_AUTH_FAILED502무의미등록한 자격증명이 아직 유효한지 확인하고 다시 등록합니다.
PROVIDER_SESSION_EXPIRED502무의미세션 로그인 작업을 다시 실행한 뒤 이어서 호출합니다.
PROVIDER_OUTCOME_UNCONFIRMED502무의미다시 보내지 말고 기관 화면에서 처리 여부를 먼저 확인합니다.
COMPLIANCE_TOS_VERSION_OUTDATED403무의미콘솔 기본정보에서 약관에 다시 동의합니다.

PROVIDER_OUTCOME_UNCONFIRMED 는 되돌릴 수 없는 작업(발행·신고·신청)을 보냈는데 기관이 받았는지 확인하지 못한 상태입니다. 다시 보내면 두 번 처리될 수 있으니, 오류 메시지에 확인할 기관 화면이 적혀 있으면 그 화면에서, 없으면 해당 기관 사이트에서 결과를 먼저 확인합니다.

전체 코드

아래 표는 호출자가 받을 수 있는 코드 전부입니다. 결제·운영 화면 전용 코드는 넣지 않았습니다.

표의 재시도 값은 코드 자체의 성격입니다. 되돌릴 수 없는 작업(발행·신고·신청)이 실패하면 요청이 이미 기관에 닿았을 수 있어, 응답의 retryable 은 그와 상관없이 false 로 옵니다 — 응답 값을 따르세요.

인증·권한

코드HTTP재시도설명
AUTH_CREDENTIAL_MISSING401무의미인증 헤더 누락
AUTH_CREDENTIAL_INVALID401무의미client_credential 또는 JWT 위조/만료
AUTH_JWT_EXPIRED401무의미JWT 만료(콘솔 사용자/관리자)
AUTH_REQUIRED401무의미기관 세션 재료(쿠키/토큰) 없음 — MCP session login 필요
AUTHZ_FORBIDDEN403무의미자원 접근 권한 없음
AUTHZ_ADMIN_ROLE_REQUIRED403무의미운영자 역할 필요

정책·한도

코드HTTP재시도설명
POLICY_TIER_FORBIDDEN403무의미지금 요금제에서는 쓸 수 없는 요청입니다.
POLICY_ENV_FORBIDDEN403무의미이 키로 쓸 수 없는 환경(샌드박스, 데모, 정식 중 하나)을 호출했습니다.
POLICY_PAID_REQUIRED402무의미정식 환경을 쓸 수 있는 유료 요금제(PRO 또는 멀티계정 요금제)가 아니거나 결제가 일시 중지된 상태입니다.
POLICY_QUOTA_EXCEEDED429무의미테스트 환경 일 100 사용 토큰 한도 초과(KST 00:00 리셋). 단위는 회가 아니다 — 액션마다 깎이는 토큰이 다르고 기본값은 1 이다
POLICY_RATE_LIMIT_EXCEEDED429가능분당 요청 수 한도 초과
POLICY_PROVIDER_FORBIDDEN403무의미요금제/상품에서 허용되지 않는 provider/action
POLICY_FEATURE_DISABLED403무의미Feature Flag 비활성

요청 검증

코드HTTP재시도설명
RESOURCE_NOT_FOUND404무의미자원 미존재
RESOURCE_CONFLICT409무의미자원 상태 충돌
RESOURCE_GONE410무의미자원이 폐기됨(soft delete 등)
VALIDATION_INVALID_FIELD400, 422무의미형식이나 타입이 틀렸습니다. 상태가 둘이고 뜻이 다릅니다: 라우트나 도메인 검사에서 걸리면 400, 요청 본문 검증에서 걸리면 422 이고 error.fields 에 필드별 안내가 옵니다. 코드만 보고 분기하지 말고 HTTP 상태도 함께 보세요.
VALIDATION_MISSING_FIELD400무의미필수 필드 누락
VALIDATION_SEMANTIC_ERROR422무의미형식은 맞으나 의미가 잘못됨
VALIDATION_ENV_SCOPE_MISMATCH422무의미env_scope가 자원/요청 간 불일치
CREDENTIAL_PAYLOAD_UNREADABLE400가능연동 저장 때 암호화된 입력을 서버 키로 풀지 못함(오래 열어 둔 화면이 옛 공개키로 암호화 등 - 입력 오류가 아니다). 화면을 새로 고친 뒤 다시 입력하면 풀린다
CREDENTIAL_OWNERSHIP_DENIED400무의미지정한 연동 계정(account_link_id)을 찾을 수 없거나 이 계정의 것이 아님. 상품 로그인 라우트(400)와 Job 실행 중 확인(FAILED)에서 난다. 콘솔 연동 목록의 계정 ID 를 확인한다. Job 제출 때의 같은 확인은 존재 여부를 숨기려고 RESOURCE_NOT_FOUND(404)다

자격증명 한도

코드HTTP재시도설명
ACCOUNT_LINK_QUOTA_EXCEEDED409무의미통합사(desktop_agent) Plan의 max_active_account_links 시트 한도 초과(용량 충돌 — 시간창 레이트리밋이 아니므로 429 대신 409, SeatLimitPort, AccountLinkService.link)

멱등성·작업

코드HTTP재시도설명
IDEMPOTENCY_KEY_CONFLICT409무의미같은 Idempotency-Key로 다른 본문이 들어옴
IDEMPOTENCY_KEY_REQUIRED400무의미멱등성 요구 엔드포인트에 키 누락
JOB_INVALID_TRANSITION409무의미허용되지 않는 상태 전이
JOB_NOT_FOUND404무의미존재하지 않는 job_id
JOB_TIMEOUT504가능Job 처리 타임아웃(전체 시한 초과)
JOB_ACTION_NOT_REGISTERED400무의미미등록 (provider, action) 쌍

쓰기 확인

코드HTTP재시도설명
WRITE_CONFIRMATION_REQUIRED400무의미확인 발급물 없이 쓰기를 요청했다. 응답의 error.confirmation_token 에 새 토큰, error.preview 에 미리보기가 실린다 — 그 내용을 고객에게 보여 주고 같은 본문의 params.confirmation_token 에 그 토큰을 넣어 다시 호출한다. MCP 는 -32602 + data.confirmation_token
WRITE_CONFIRMATION_INVALID409무의미없음 · 만료(10분) · 이미 소비 · 본문/호출자/plane 불일치. 어느 조건인지 알리지 않는다(오라클 금지). 토큰 없이 다시 호출하면 새 확인을 받는다

외부 기관

코드HTTP재시도설명
PROVIDER_TIMEOUT_CONNECT504가능connect 단계 타임아웃
PROVIDER_TIMEOUT_READ504가능read 단계 타임아웃
PROVIDER_TIMEOUT_OVERALL504가능전체 시한 초과
PROVIDER_IP_REJECTED502가능기관에서 IP 차단/리젝(403/429/connection_reset/tls_fail)
PROVIDER_UNAVAILABLE503가능기관 서비스 장애
PROVIDER_BAD_RESPONSE502무의미기관 응답이 계약과 불일치
PROVIDER_AUTH_FAILED502무의미기관 자체 인증 실패(자격증명 만료 등)
PROVIDER_SESSION_EXPIRED502무의미기관 세션 만료(예: NPS Nexacro ErrorCode=-2001, NHIS MainNoXecure HTTP 2xx + 빈 본문)
PROVIDER_BUSINESS_ERROR200무의미기관 HTTP 200 + 비즈 거부
PROVIDER_VALIDATION_ERROR200무의미기관 4xx 검증 거부
PROVIDER_UPSTREAM_ERROR200가능기관 5xx 재시도 소진 후 FAILED
PROVIDER_OUTCOME_UNCONFIRMED502무의미되돌릴 수 없는 기관 쓰기(발행·신고·신청)를 보냈으나 승낙도 거절도 확인하지 못함. 재시도 금지 — 이미 처리됐을 수 있어 이중 처리가 된다. 메시지에 확인 화면을 싣는다
PROVIDER_PREREQUISITE_REQUIRED409무의미고객이 기관 쪽에서 아직 하지 않은 일(가입 · 이용 동의 · 인증서 등록)이 있어 못 한다. 보낸 값은 맞으므로 400 이 아니고, 우리 쪽에서 기다린다고 풀리지 않으므로 재시도도 아니다. 어느 코드가 그것인지와 고객에게 할 말은 상품이 선언한다

점검·내부

코드HTTP재시도설명
INTERNAL_ERROR500무의미분류 불가 내부 오류
INTERNAL_DB_ERROR500가능DB 처리 실패
INTERNAL_INVARIANT_VIOLATED500무의미불변식 위반(트리거/AuthPolicy 방어, severity=CRITICAL)
MAINTENANCE_UPSTREAM503가능상류 의존 점검
SERVICE_UNAVAILABLE503가능그 환경에 아직 활성 암호화 키가 없다

약관·컴플라이언스

코드HTTP재시도설명
COMPLIANCE_TOS_VERSION_OUTDATED403무의미필수 약관 미동의 또는 consent_version 불일치
COMPLIANCE_PAYMENT_CONSENT_MISSING403무의미결제 도메인 진입 시 결제 관련 약관 미동의
COMPLIANCE_PROVIDER_CONSENT_MISSING403무의미(레거시) 외부 기관 provider_data_share 미동의
COMPLIANCE_DELETION_IN_PROGRESS403무의미주체가 진행 중인 삭제 요청에 묶여 호출 차단
COMPLIANCE_INVALID_TRANSITION409무의미컴플라이언스 리소스의 비허용 상태 전이 시도
COMPLIANCE_DUPLICATE_REQUEST409무의미동일 target에 활성 컴플라이언스 요청 존재
COMPLIANCE_SOLE_OWNER_BLOCK409무의미단독 OWNER 사용자 삭제 요청 승인 시도 차단
COMPLIANCE_RETENTION_PURGE_FAILED500무의미deletion-triggered retention purge 실행 실패

작업이 실패했을 때

작업이 FAILED 나 TIMEOUT 으로 끝나면 상태 응답의 error 에 code · message · retryable · provider_error_ref 가 같은 뜻으로 담깁니다. trace_id 대신 기관 쪽 HTTP 상태(upstream_status)가 붙습니다. HTTP 응답이 200 이어도 작업은 실패일 수 있으니 상태를 함께 확인합니다 — 작업 처리 흐름.