---
template: policy-doc@1
doc_id: 03-error-codes
title: 에러 코드 — 기능 블록 규칙 · 코드값 비유일성 · 같은 표의 비에러 코드
config: ../_meta/template-config.yaml
last_verified: 4d798f55
policies:
  - id: ERROR_BLOCK_RULE
    status: active-prod
    evidence: [S-constant, A-comment]
    limitations:
      - 블록 번호가 실제로 그 기능을 뜻하는지는 주석과 배치가 말할 뿐 기계가 판정하지 못한다
      - 세 상수 파일 밖에도 실패 응답 값이 있을 수 있다. 이 문서의 사정거리는 이 세 파일이다
    anchors:
      - insuniverse-server/apps/api/src/constants/admin.constant.ts:4
      - insuniverse-server/apps/api/src/constants/admin.constant.ts:13
      - insuniverse-server/apps/api/src/constants/admin.constant.ts:11
      - insuniverse-server/apps/api/src/constants/api.constant.ts:28
      - insuniverse-server/apps/api/src/constants/api.constant.ts:59
      - insuniverse-server/apps/api/src/constants/client.constant.ts:25
      - insuniverse-server/apps/api/src/constants/client.constant.ts:29
  - id: ERROR_CODE_NOT_UNIQUE
    status: active-prod
    evidence: [S-constant, S-contract]
    limitations:
      - 같은 코드값을 쓰는 두 선언이 정말 다른 뜻인가는 기계가 판정하지 못한다. 이 문서는 중복이 실재한다는 사실까지만 쓴다
      - 파일을 건너선 중복은 이 문서가 열거하지 않는다. 한 파일 안 충돌만 이름으로 연다
    anchors:
      - insuniverse-server/apps/api/src/constants/admin.constant.ts:18
      - insuniverse-server/apps/api/src/constants/admin.constant.ts:63
      - insuniverse-server/apps/api/src/constants/api.constant.ts:52
      - insuniverse-server/apps/api/src/constants/api.constant.ts:54
      - insuniverse-server/apps/api/src/constants/api.constant.ts:57
      - insuniverse-server/apps/api/src/constants/api.constant.ts:60
      - insuniverse-server/apps/api/src/constants/api.constant.ts:7
      - insuniverse-server/apps/api/src/constants/client.constant.ts:7
  - id: NON_E_RESPONSE_CODES
    status: active-prod
    evidence: [S-constant, S-contract]
    limitations:
      - 비에러 형태의 값이 앞으로 더 늘 수 있다. 이 문서는 동결 시점에 관측된 것만 연다
    anchors:
      - insuniverse-server/apps/api/src/constants/admin.constant.ts:1
      - insuniverse-server/apps/api/src/constants/api.constant.ts:13
      - insuniverse-server/apps/api/src/constants/client.constant.ts:12
      - insuniverse-server/apps/api/src/constants/client.constant.ts:16
      - insuniverse-server/apps/api/src/constants/api.constant.ts:101
      - insuniverse-server/apps/api/src/constants/api.constant.ts:105
      - insuniverse-server/apps/api/src/constants/api.constant.ts:108
      - insuniverse-server/apps/api/src/constants/api.constant.ts:109
      - insuniverse-server/apps/api/src/constants/admin.constant.ts:83
      - insuniverse-server/apps/api/src/constants/admin.constant.ts:88
      - insuniverse-server/apps/api/src/constants/api.constant.ts:1
      - insuniverse-server/apps/api/src/constants/client.constant.ts:8
---

# 에러 코드 — 기능 블록 규칙 · 코드값 비유일성 · 같은 표의 비에러 코드

이 문서는 실패 응답에 실리는 코드값이 **어떤 규칙으로 만들어지는가**, 그리고 그 규칙이 **무엇을 보장하지 못하는가**를 정한다. 규칙은 앞 두 자리로 기능 갈래를 나누는 것 하나이고, 보장하지 못하는 것은 값의 유일성이다.

코드 식별자가 몇 갈래인가는 여기 없다 — `02-identifier-namespaces.md` 소관이며 이 문서는 그중 에러 갈래 하나를 자세히 쓴다. 각 코드의 뜻과 전수도 여기 없다. 전수는 `../_meta/index/codes/error.yaml` 이 소유한다.

## 정책 (기획)

### ERROR_BLOCK_RULE

실패 응답의 코드값은 **앞 글자 하나와 숫자 네 자리**로 된 값이고, 네 자리 중 **앞 두 자리가 기능 갈래**를 나타낸다. 뒤 두 자리는 그 갈래 안의 일련번호다. 갈래 번호와 이름의 대응은 각 상수 파일 머리의 안내 주석이 선언한다.

**그 안내 주석과 실제 코드 배치가 파일마다 다르게 어긋나 있다.** 어긋남은 두 방향이다 — 안내에는 있는데 실제 코드가 없는 갈래가 있고, 실제 코드는 있는데 안내에 없는 갈래가 있다. 한 파일에서는 안내가 선언한 번호와 실제 코드가 쓰는 번호가 아예 다르다.

| 파일 | 안내에만 있는 갈래 | 실제 코드에만 있는 갈래 | 안내와 실제가 어긋난 자리 |
|---|---|---|---|
| 관리자 상수 | 인증 | 광고 · 영업대리점 | 청구서 갈래 번호를 공통 갈래가 함께 쓴다 |
| 이용자 API 상수 | 분석 | 손해사정서비스 | 분석 갈래를 안내는 넷째 번호로 선언했으나 실제 코드는 셋째 번호를 쓴다 — 알림톡과 같은 번호가 된다 |
| 고객사 API 상수 | 없음 | 없음 | 없음 |

**그래서 갈래 번호만으로 기능을 판정하지 않는다.** 안내 주석은 의도를 말하고 실제 배치는 현행을 말하며, 둘이 다른 자리에서는 현행이 답이다.

온보딩에서 자주 묻는 값 하나를 여기서 답한다 — **기업 권한 없음**을 뜻하는 코드가 관리자 상수에 있고 그 값의 갈래 번호는 넷째다. 관리자 상수의 안내 주석에는 넷째 번호가 없다. 같은 번호가 이용자 API 상수의 안내에는 있으나 그것은 다른 파일의 다른 갈래(분석)이며 이 값과 무관하다.

### ERROR_CODE_NOT_UNIQUE

**같은 코드값이 한 파일 안에서 두 번 이상 선언돼 있다.** 서로 다른 실패 상황에 같은 값이 붙어 있으며, 뒤에 선언된 쪽이 앞을 덮지 않는다 — 둘 다 각자의 이름으로 살아 있고 호출부가 이름으로 골라 쓴다.

그래서 **코드값은 조회 키가 아니다.** 값 하나를 들고 "이게 무슨 실패냐" 고 물으면 답이 하나로 정해지지 않는다. 조회 키는 그 값이 **어느 파일의 어느 이름으로 선언됐는가** 하는 쌍이며, 이것은 `02-identifier-namespaces.md` 가 정한 규칙이 에러 축에서 나타난 형태다.

중복을 남긴 판단 자체는 코드에 기록돼 있다 — 조직·계약·회원 갈래를 새로 만들 때 "호출 맥락이 갈리므로 충돌하지 않는다" 고 적어 두었다. 이 문서는 그 판단의 옳고 그름을 따지지 않고 중복이 실재한다는 사실만 남긴다.

### NON_E_RESPONSE_CODES

**같은 상수 표에 실패가 아닌 값과 에러 형태가 아닌 값이 함께 산다.** 표 이름이 에러 상수라고 해서 그 안이 전부 에러 코드인 것은 아니다.

같이 사는 것은 네 갈래다.

| 갈래 | 무엇인가 |
|---|---|
| 성공 코드 | 요청이 성공했을 때 같은 자리에 실리는 값. 실패 값과 형태가 다르다 |
| 외부 연동 실패 계열 | 어느 외부 연동사에서 실패했는지를 앞 글자로 구분하는 값 |
| 푸시 토큰 계열 | 푸시 발송 축이 쓰는 별도 접두를 가진 값 |
| 이름을 그대로 값으로 쓴 것 | 숫자 체계를 따르지 않고 상황 이름 자체를 값으로 둔 것. 화면이 이 문자열을 그대로 읽는다 |

**응답에서 이 값이 실리는 칸의 이름도 하나가 아니다.** 운영사·이용자 축과 고객사 축이 서로 다른 이름을 쓴다. 그래서 "응답의 코드 칸" 이라고만 말하면 어느 축 이야기인지 정해지지 않는다.

## 강제 지점 (개발)

### ERROR_BLOCK_RULE

- 강제 방식: **강제하는 코드가 없다.** 블록 규칙은 상수 파일 머리의 안내 주석(`/** … */`)과 본문 사이사이의 구획 주석(`// 이름 (NN)`)으로만 표현되며, 값을 그 규칙에 맞추는 검사기는 이 저장소에도 제품에도 없다. 근거 등급에 `A-comment` 가 들어가는 이유가 그것이고, 그래서 아래 표가 두 계열을 **각각** 싣는다.
- 표의 `출처` 열 — `legend` 는 파일 머리 안내 주석, `inline` 은 본문 구획 주석이다. 두 계열을 합치면 어긋남이 사라진다.
- 아래 표는 동결 SHA 기준 세 파일에서 다시 유도한 것이며, 계획서 게이트 `#6` 이 행 집합과 두 계열의 어긋남을 함께 대조한다. **행 수를 여기 적지 않는다** — 그 계수를 대조하는 검사가 없어 표가 바뀌어도 산문만 낡는다.

| 파일 | 블록 | 이름 | 출처 |
|---|---|---|---|
| `admin` | `01` | 관리자 | legend |
| `admin` | `02` | 기업 | legend |
| `admin` | `03` | FC | legend |
| `admin` | `06` | 인증 | legend |
| `admin` | `08` | 엑셀 | legend |
| `admin` | `09` | 청구서 | legend |
| `admin` | `01` | 관리자 | inline |
| `admin` | `02` | 기업 | inline |
| `admin` | `03` | FC | inline |
| `admin` | `07` | 광고 | inline |
| `admin` | `08` | 엑셀 | inline |
| `admin` | `09` | 청구서 | inline |
| `admin` | `09` | 공통 | inline |
| `admin` | `10` | 영업대리점 | inline |
| `api` | `01` | 구독 | legend |
| `api` | `02` | 주문/결제 | legend |
| `api` | `03` | 알림톡 | legend |
| `api` | `04` | 분석 | legend |
| `api` | `05` | 분석결과 | legend |
| `api` | `06` | 인증 | legend |
| `api` | `07` | FC | legend |
| `api` | `08` | 기타 | legend |
| `api` | `01` | 구독 | inline |
| `api` | `02` | 주문/결제 | inline |
| `api` | `03` | 알림톡 | inline |
| `api` | `03` | 분석 | inline |
| `api` | `05` | 분석결과 | inline |
| `api` | `06` | 인증 | inline |
| `api` | `07` | FC | inline |
| `api` | `08` | 그 외 | inline |
| `api` | `09` | 손해사정서비스 | inline |
| `client` | `00` | 기본요청 | legend |
| `client` | `01` | 계약정보 | legend |
| `client` | `02` | 주문 | legend |
| `client` | `03` | 분석 | legend |
| `client` | `00` | 기본요청 | inline |
| `client` | `01` | 계약정보 | inline |
| `client` | `02` | 주문 | inline |
| `client` | `03` | 분석 | inline |

- `admin` = `insuniverse-server/apps/api/src/constants/admin.constant.ts` · `api` = `insuniverse-server/apps/api/src/constants/api.constant.ts` · `client` = `insuniverse-server/apps/api/src/constants/client.constant.ts`
- 안내 주석의 한 행 — `insuniverse-server/apps/api/src/constants/admin.constant.ts:4`. 구획 주석의 한 행 — `insuniverse-server/apps/api/src/constants/admin.constant.ts:13`. 그 갈래의 실제 값 — `insuniverse-server/apps/api/src/constants/admin.constant.ts:11`
- 안내와 구획이 서로 다른 번호를 쓰는 자리 — 안내 `insuniverse-server/apps/api/src/constants/api.constant.ts:28` 이 분석을 `04` 로 선언하는데 구획 `insuniverse-server/apps/api/src/constants/api.constant.ts:59` 는 `03` 을 쓴다. 같은 파일의 알림톡 구획이 이미 `03` 이라 두 갈래가 한 번호를 공유한다.
- 4/4 로 일치하는 파일 — `insuniverse-server/apps/api/src/constants/client.constant.ts:25` 이 선언한 갈래가 `insuniverse-server/apps/api/src/constants/client.constant.ts:29` 부터의 배치와 어긋나지 않는다.
- `E0401` = `CORP_FORBIDDEN` (기업 권한이 없습니다) — `insuniverse-server/apps/api/src/constants/admin.constant.ts:79`. 갈래 번호 `04` 는 이 파일의 안내 주석 여섯 항목(`01` · `02` · `03` · `06` · `08` · `09`) 어디에도 없다. `api` 안내가 선언한 `04`(분석)는 다른 파일의 다른 갈래다.

### ERROR_CODE_NOT_UNIQUE

- 강제 방식: **강제 지점이 없다.** 값 중복을 막는 검사가 없어 같은 값이 여러 이름에 붙을 수 있고, 실제로 붙어 있다. 응답 계약이 이 값을 문자열로만 규정하는 것이 그 이유다 — `insuniverse-server/apps/api/src/constants/api.constant.ts:7` · `insuniverse-server/apps/api/src/constants/client.constant.ts:7`
- 아래는 **한 파일 안에서** 두 번 이상 선언된 코드값 전건이다. 동결 SHA 기준으로 다시 유도했으며 계획서 게이트 `#7` 이 행 단위로 대조한다.

| 코드값 | 파일 | 심볼 | 행 |
|---|---|---|---|
| `E0101` | `admin` | `INVALID_ACCOUNT_ID` | 11 |
| `E0101` | `admin` | `NOT_FOUND_ADMIN` | 14 |
| `E0202` | `admin` | `CONTRACT_DATE_DUPLICATE` | 18 |
| `E0202` | `admin` | `DUPLICATE_CONTRACT_PER_ORG` | 63 |
| `E0301` | `admin` | `INVALID_LOGIN_ID_FORMAT` | 26 |
| `E0301` | `admin` | `ORG_NOT_FOUND` | 64 |
| `E0302` | `admin` | `INVALID_PASSWORD_FORMAT` | 27 |
| `E0302` | `admin` | `ORG_AGENCY_MISMATCH` | 65 |
| `E0901` | `admin` | `DUPLICATE_INVOICE` | 50 |
| `E0901` | `admin` | `DUPLICATE_DATA` | 57 |
| `E0214` | `api` | `ALREADY_SETTLEMENT_CONFIRMED` | 52 |
| `E0214` | `api` | `EXPIRED_ACCESS_LINK` | 54 |
| `E0301` | `api` | `FAILED_SEND` | 57 |
| `E0301` | `api` | `ALREADY_ANALYZED` | 60 |

- 대표 자리 두 곳 — `insuniverse-server/apps/api/src/constants/admin.constant.ts:18` 과 `insuniverse-server/apps/api/src/constants/admin.constant.ts:63` 이 같은 `E0202` 를 서로 다른 뜻으로 쓴다. `insuniverse-server/apps/api/src/constants/api.constant.ts:52` 와 `insuniverse-server/apps/api/src/constants/api.constant.ts:54` 도 같은 `E0214` 다.
- 두 갈래가 한 번호를 공유하면서 생긴 충돌 — `insuniverse-server/apps/api/src/constants/api.constant.ts:57` (알림톡 발송 실패)과 `insuniverse-server/apps/api/src/constants/api.constant.ts:60` (이미 사용된 분석 이용권)이 같은 `E0301` 이다. `ERROR_BLOCK_RULE` 의 어긋남이 그대로 값 충돌로 이어진 자리다.
- 조회 키는 `(선언 파일, 심볼)` 쌍이다. 코드 인덱스도 같은 규칙을 쓴다 — `../_meta/index/codes/error.yaml` 의 조인 키가 코드값이 아니라 저장소 한정 모듈 경로 + 선언 이름이다. 규칙의 정본은 `02-identifier-namespaces.md` `SYMBOL_JOIN_KEY` 다.

### NON_E_RESPONSE_CODES

- 강제 방식: **응답 계약이 코드 칸을 문자열로만 규정한다.** 열거 타입이 아니라 `string` 이라 어떤 형태든 실릴 수 있다 — `insuniverse-server/apps/api/src/constants/api.constant.ts:1` · `insuniverse-server/apps/api/src/constants/client.constant.ts:8`. 칸 이름도 축마다 다르다.
- 성공 코드 — `0000` 이 두 파일에 있다. `insuniverse-server/apps/api/src/constants/admin.constant.ts:1` · `insuniverse-server/apps/api/src/constants/api.constant.ts:13`. 고객사 축은 `S0000` 을 쓴다 — `insuniverse-server/apps/api/src/constants/client.constant.ts:12`
- 외부 연동 실패 계열 — `IE9999` · `CE9999` · `TE9999` · `AE9999` · `VE9999` 가 한 묶음으로 선언돼 있다. `insuniverse-server/apps/api/src/constants/api.constant.ts:101` 부터 `insuniverse-server/apps/api/src/constants/api.constant.ts:105` 까지다.
- 푸시 토큰 계열 — `FC9999` · `FC0001`. `insuniverse-server/apps/api/src/constants/api.constant.ts:108` · `insuniverse-server/apps/api/src/constants/api.constant.ts:109`
- 이름을 그대로 값으로 쓴 것 — `SEAT_BELOW_CONTRACT` · `SEAT_BELOW_CONTRACT_WARN`. `insuniverse-server/apps/api/src/constants/admin.constant.ts:83` · `insuniverse-server/apps/api/src/constants/admin.constant.ts:88`. 화면이 이 문자열을 그대로 읽는다는 것이 같은 자리 주석에 적혀 있다.
- 형태는 `E` 인데 기능 블록 체계 밖인 값도 있다 — 고객사 축의 `E9999` 다. `insuniverse-server/apps/api/src/constants/client.constant.ts:16`
- **개수를 적지 않는다.** 이 갈래의 계수는 `../_meta/extraction-manifest.yaml` 이 동결하지 않았고, 자체로 센 수를 문서에 싣지 않는다는 것이 이 PRD 의 제약이다. 전수는 `../_meta/index/codes/error.yaml` 이 소유한다.

## 적용 범위 (actor × 서비스)

| 정책 id | server | site | admin |
|---|---|---|---|
| ERROR_BLOCK_RULE | 선언 · 안내 주석 3벌 | 값 소비 | 값 소비 |
| ERROR_CODE_NOT_UNIQUE | 중복 선언이 실재하는 자리 | — | — |
| NON_E_RESPONSE_CODES | 선언 3벌 · 응답 계약 2벌 | 값 소비 | 이름형 값의 화면 분기 |

`—` = 그 서비스가 이 정책의 경로에 등장하지 않음.

이 표의 열은 서비스 3종이며 actor 는 열이 아니다. 에러 코드는 로그인 주체별로 갈리지 않고 **어느 축의 응답인가**로 갈린다.

## 예외·폴백

| 정책 id | 예외 조건 | 폴백 동작 | 확인 근거 |
|---|---|---|---|
| ERROR_BLOCK_RULE | 안내 주석에만 있고 실제 코드가 없는 갈래 | 규칙의 결손이 아니라 미사용이다. 값을 지어내지 않는다 | `insuniverse-server/apps/api/src/constants/api.constant.ts:28` |
| ERROR_BLOCK_RULE | 실제 코드에만 있고 안내에 없는 갈래 | 현행이 답이다. 안내 주석은 갱신되지 않았다 | `insuniverse-server/apps/api/src/constants/admin.constant.ts:79` |
| ERROR_BLOCK_RULE | 안내와 구획이 서로 다른 번호를 쓰는 자리 | 구획 번호가 현행이며 그 결과 두 갈래가 한 번호를 공유한다 | `insuniverse-server/apps/api/src/constants/api.constant.ts:59` |
| ERROR_CODE_NOT_UNIQUE | 코드값만으로 실패 사유를 조회할 때 | 답이 하나로 정해지지 않는다. 선언 자리를 함께 지정한다 | `insuniverse-server/apps/api/src/constants/admin.constant.ts:63` |
| ERROR_CODE_NOT_UNIQUE | 뒤에 선언된 값이 앞을 덮는지 확인할 때 | 덮지 않는다. 둘 다 각자의 이름으로 살아 있다 | `insuniverse-server/apps/api/src/constants/api.constant.ts:54` |
| NON_E_RESPONSE_CODES | 코드 칸이 에러 값만 담는다고 가정할 때 | 성공 값도 같은 칸에 실린다 | `insuniverse-server/apps/api/src/constants/api.constant.ts:13` |
| NON_E_RESPONSE_CODES | 코드 칸의 이름이 하나라고 가정할 때 | 축마다 다르다. 고객사 축은 다른 이름을 쓴다 | `insuniverse-server/apps/api/src/constants/client.constant.ts:8` |
| NON_E_RESPONSE_CODES | 값이 항상 숫자 체계를 따른다고 가정할 때 | 이름 자체를 값으로 쓴 것이 있고 화면이 그 문자열을 읽는다 | `insuniverse-server/apps/api/src/constants/admin.constant.ts:83` |

## 연혁

릴리스 태그가 존재하지 않는다. 릴리스 열은 `—` 로 두고 커밋 SHA 로 추적한다.

| 릴리스 | 날짜 | SHA | 변경 요약 |
|---|---|---|---|
| — | 2025-04-01 | `689a9bcd` | 이용자 API 상수에 손해사정서비스 구획 신설 — 안내 주석에 없는 갈래가 처음 생김 |
| — | 2025-06-25 | `4aa4ed1f` | 관리자 상수에 영업대리점 구획 신설 — 안내 주석에 없는 두 번째 갈래 |
| — | 2026-05-20 | `8be772db` | 기업↔기업상품 1:N 개편 — 관리자 상수의 파일내 코드값 충돌이 다섯 종으로 늘고 `E0401` 이 신설됨 |
| — | 2026-06-23 | `5d1dc124` | 초대 링크 접근 유효성 검사 추가 — 이용자 API 상수에 `E0214` 두 번째 선언 |
| — | 2026-07-11 | `0147d2c0` | 구독계정수 하한 판정 추가 — 이름을 그대로 값으로 쓴 상수 2건 신설 |
