Cupix::Errors::Argument: No mapping found for [id] in order to sort on
RCA: Cupix::Errors::Argument: No mapping found for [id] in order to sort on
Overview#
What Happened#
cupixvista-api (= tesla Rails 앱의 vista 배포) 의 검색 API 에서, 클라이언트가 대상 Elasticsearch 인덱스에 매핑되지 않은 필드(id)를 정렬 기준으로 요청하면 ES 가 BadRequest 를 반환한다. tesla 는 이를 Cupix::Errors::Argument (ARG13000) 로 감싸는데, 이 예외가 server_error_controller 에서 HTTP 500 으로 매핑되어 Error Tracking 에 서버 에러로 집계된다. 실제로는 잘못된 정렬 파라미터라는 클라이언트 입력 검증 실패(400 성격)이다. 16개월간 473회 발생(<1/day).
Quick Facts#
| Field | Value |
|---|---|
| exception.class | Cupix::Errors::Argument (code ARG13000) |
| exception.message | No mapping found for [id] in order to sort on |
| top_frame | app/repositories/base_repository.rb:87 |
| env | production |
Affected Teams#
| Team / Domain | Error Count | Impact |
|---|---|---|
| cupixvista-api (tesla) | 473 (16mo) | 잘못된 sort/order_by 파라미터로 검색 요청 시 HTTP 500 응답. 정상 파라미터 사용자에게는 영향 없음 |
Timeline#
- 2025-06-23 14:40 KST — 최초 발생 (first_seen)
- 2026-07-08 20:45 KST — 최근 발생 (last_seen). 이후 14d 로그 보존 창(now-14d) 내 재발 로그/span 0건
- 2026-08-04 — RCA 수행. 대상 span/log 모두 retention 밖이라 미검색
Error Log#
No mapping found for [id] in order to sort on
Impact#
- Service:
cupixvista-api(실제 앱 = tesla) - 발생 횟수: 473
- 최초 발생: 2025-06-23 14:40 KST
- 최근 발생: 2026-07-08 20:45 KST
Root Cause Summary#
검색 API 의 정렬 파라미터(sort / order_by / sort_order_by)는 클라이언트가 지정하며, SearchableController#build_sort_query (app/controllers/concerns/searchable_controller.rb:399-402) 는 미리 정의된 5개 alias(SORTABLE_FIELDS_ALIAS)에 해당하지 않는 값을 그대로 order_by.to_sym 으로 ES sort 절에 넘긴다. 대상 인덱스에 매핑이 없는 필드(예: id)를 정렬 기준으로 주면 Elasticsearch 가 illegal_argument_exception: No mapping found for [id] in order to sort on 을 담은 BadRequest 를 반환한다. BaseRepository#search (app/repositories/base_repository.rb:83-87) 는 이 BadRequest 를 rescue 하여 root_cause reason 을 실어 Cupix::Errors::Argument (ARG13000) 를 raise 한다. 문제는 ARG13000 의 의미가 "Invalid parameter in sort/order"(클라이언트 입력 오류, TSLA-1895 설계상 400)임에도, ServerErrorController (app/controllers/concerns/server_error_controller.rb:7-8) 가 Cupix::Errors::Argument 를 Cupix::Errors::System 과 함께 system_500_error 로 rescue 하여 HTTP 500 으로 응답한다는 점이다. 즉 서버 로직 결함이 아니라 잘못된 정렬 필드라는 클라이언트 입력 검증 실패가 상태 코드 매핑 오류로 500 서버 에러(→ Error Tracking noise)로 나타난다.
Technical Analysis#
Code Path#
- Entry point:
app/controllers/concerns/searchable_controller.rb:22— 검색 컨트롤러가query_option을 만들 때 클라이언트 파라미터를 정렬 기준으로 사용
def get_query_option(enable_current_team: true)
_query_option = QueryOption.new(
per_page: params[:per_page],
page: params[:page],
sort: order_by(params[:sort], params[:order_by], params[:sort_order_by]),
- 정렬 절 생성:
app/controllers/concerns/searchable_controller.rb:399-402— alias 5개(name/creator/user/rank/group_type)에 없으면 파라미터 값을 그대로 sort key 로 사용. 필드가 인덱스에 매핑되어 있는지 검증하지 않는다
def build_sort_query(sort, order_by)
sort_key = SORTABLE_FIELDS_ALIAS.include?(order_by) ? SORTABLE_FIELDS_ALIAS[order_by] : order_by.to_sym
{ sort_key => { order: sort.to_sym, missing: '_last' } }
end
- Failure point:
app/repositories/base_repository.rb:83-87— ES 가 매핑 없는 필드 정렬을 거부하며BadRequest를 던지고, root_cause reason(No mapping found for [id] in order to sort on)을 실어ARG13000으로 변환
rescue Elasticsearch::Transport::Transport::Errors::BadRequest => e
_message = JSON.parse(e.message.split(/\[\d{3}\]\s/i)[1]) rescue {}
_reason = _message['error']['root_cause'][0]['reason'] rescue nil
raise Cupix::Errors::Argument.new(code: 'ARG13000', reason: _reason)
- 상태 코드 매핑 오류:
app/controllers/concerns/server_error_controller.rb:7-8—Cupix::Errors::Argument를Cupix::Errors::System과 함께 500 으로 rescue.ClientErrorController의client_400_errorrescue 목록(Parameter,Unknown,Resource,Session,Entity,Billing,InvalidState,Siteinsights)에는Argument가 없다
rescue_from Cupix::Errors::System,
Cupix::Errors::Argument, with: :system_500_error
- 설계 의도와의 불일치:
ARG13000의 정의 메시지는 클라이언트 입력 오류를 뜻하며, TSLA-1895 설계 문서는 이 코드를 400 으로 명시했으나 런타임 구현은 500 으로 매핑된다
ARG13000:
message: Invalid parameter in sort/order
| 400 | ARG13000 | ES BadRequest (잘못된 query DSL 등) — root_cause reason 전달 |
- 기대 동작: 매핑되지 않은 정렬 필드는 클라이언트 입력 오류이므로 400(또는 alias 화이트리스트 검증으로 사전 차단)로 응답해야 한다.
- 실제 동작:
Cupix::Errors::Argument→system_500_error→ 500 서버 에러로 응답 및 Error Tracking 집계.
Log Evidence#
cupixvista-api 가 tesla 임을 확인한 span 조회 (production 스택트레이스가 /var/app/current/app/repositories/base_repository.rb 를 가리킴):
service:cupixvista-api status:error
{
"component": "action_pack",
"env": "production",
"error": {
"handling": "handled",
"message": "Capture not found",
"stack": "/var/app/current/app/repositories/base_repository.rb:353:in `show': Capture not found (Cupix::Errors::NotFound)\n\tfrom .../video_repository.rb:352:in `_search'\n\tfrom .../base_repository.rb:71:in `search'"
}
}
대상 에러 자체는 last_seen(2026-07-08)이 14일 로그 보존 창(now-14d, 기준일 2026-08-04) 밖이라 로그/span 모두 0건이었다. 검색한 쿼리와 결과:
service:cupixvista-api "No mapping found" -> 0 logs
service:cupixvista-api "in order to sort on" -> 0 logs
service:cupixvista-api "ARG13000" -> 0 logs
service:cupixvista-api status:error "sort" -> 0 spans
service:cupixvista-api status:error "No mapping" -> 0 spans
"in order to sort on" -> 0 spans (all services)
Representative message No mapping found for [id] in order to sort on 은 Elasticsearch 가 생성하는 고정 형태의 root_cause.reason 문자열이며 필드명([id])만 변한다. 따라서 로그가 없어도 대표 샘플은 신뢰 가능(stale 아님)하며, 근본 원인은 코드 경로로 확정된다.
Hypotheses Considered#
| # | Hypothesis | Evidence for | Evidence against | Verdict |
|---|---|---|---|---|
| H1 | 클라이언트가 매핑 없는 필드(id)로 정렬 요청 → ES BadRequest → ARG13000 이 500 으로 매핑되는 status-code 매핑 오류(noise) |
searchable_controller.rb:399-402 alias 외 필드 무검증 통과; base_repository.rb:83-87 BadRequest→ARG13000; server_error_controller.rb:7-8 Argument→500; argument.yml:196 정의 = 입력 오류; TSLA-1895 문서상 400 의도 |
— | Confirmed |
| H2 | tesla 서버 로직/ES 인덱스 매핑 결함 (실제 서버 버그) | — | reason 은 ES 표준 illegal_argument_exception; 트리거는 클라이언트가 지정한 정렬 필드; 다른 정렬 파라미터 사용 시 정상 동작 |
Rejected |
| H3 | ES 클러스터 장애/일시적 다운스트림 이슈 | — | status-board svc:cupixvista-api::unknown active 인시던트 없음; BadRequest(400)는 매핑 부재 결정적 오류이지 일시적 장애 아님; 429 circuit breaker 및 502 경로는 별도 분기(base_repository.rb:88-97) |
Rejected |
| H4 | 대표 메시지가 stale (다른 필드 변형이 현재 발생) | 필드명 [id] 만 변하는 ET 그룹핑 특성 |
last_seen 이 retention 밖이라 현재 발생 자체가 없음; 메시지 형태는 고정 ES 상수 | Rejected (moot) |
Fix Recommendation#
즉시 조치 (Critical)#
- 상태 코드 매핑 교정: 정렬 필드 미매핑은 클라이언트 입력 오류이므로 500 이 아닌 400 으로 응답해야 한다.
base_repository.rb:87이 던지는 정렬 관련ARG13000을 클라이언트 4xx 로 분류할 것. 단,Cupix::Errors::Argument를 통째로client_400_error로 옮기면 다른 사용처(entity_repository.rb:49등)에 영향을 줄 수 있으므로, ARG10060 사례(824fc506)와 동일하게 정렬 무매핑 케이스만 클라이언트 전용 예외 클래스(예:Cupix::Errors::Parameter)로 좁혀서 raise 하는 방향을 권장. 이는 프런트엔드/클라이언트 계약(응답 코드 변경) 조율이 필요하므로 별도 트랙으로 진행.
단기 개선 (1주 이내)#
- 정렬 필드 화이트리스트 검증:
build_sort_query(searchable_controller.rb:399-402) 진입 시 모델별 sortable 필드 목록(또는 인덱스 매핑)에 대해order_by를 검증하고, 허용되지 않은 값이면Cupix::Errors::Parameter ARG10001(400)로 즉시 반려. ES 까지 나가지 않아 불필요한 쿼리와 500 을 원천 차단.
장기 개선 (재발 방지)#
- 검색 파라미터 스키마 계약화: 컨트롤러 진입 시점에 정렬/필터 파라미터를 모델별 스키마로 검증하는 공통 레이어 도입.
ARG13000처럼 "입력 오류인데 서버 예외 계층에 묶여 500 으로 새는" 코드들을 점검하여 4xx/5xx 분류를 정합화.
Monitoring#
정렬 관련 ARG13000 발생 추이 (retention 내 재발 감지용):
service:cupixvista-api status:error "in order to sort on"
ARG13000 전체 발생량 (정렬/필터 무매핑 포함):
service:cupixvista-api "ARG13000"
Risk Assessment#
- Risk level: low
- 예상 복잡도: standard (상태 코드 매핑 변경은 클라이언트 계약 조율 필요)
Noise Verdict#
noise — 매핑되지 않은 정렬 필드라는 클라이언트 입력 검증 실패가 ARG13000 의 status-code 매핑 오류로 500 으로 새는 것일 뿐 서버 코드 결함이 아니므로 noise 로 판정한다.