ES /docs

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#

  1. 2025-06-23 14:40 KST — 최초 발생 (first_seen)
  2. 2026-07-08 20:45 KST — 최근 발생 (last_seen). 이후 14d 로그 보존 창(now-14d) 내 재발 로그/span 0건
  3. 2026-08-04 — RCA 수행. 대상 span/log 모두 retention 밖이라 미검색

Error Log#

Datadog Logs

text
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::ArgumentCupix::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 을 만들 때 클라이언트 파라미터를 정렬 기준으로 사용
app/controllers/concerns/searchable_controller.rb:18-23ruby
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 로 사용. 필드가 인덱스에 매핑되어 있는지 검증하지 않는다
app/controllers/concerns/searchable_controller.rb:399-402ruby
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 으로 변환
app/repositories/base_repository.rb:83-87ruby
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-8Cupix::Errors::ArgumentCupix::Errors::System 과 함께 500 으로 rescue. ClientErrorControllerclient_400_error rescue 목록(Parameter, Unknown, Resource, Session, Entity, Billing, InvalidState, Siteinsights)에는 Argument 가 없다
app/controllers/concerns/server_error_controller.rb:7-8ruby
rescue_from Cupix::Errors::System,
            Cupix::Errors::Argument, with: :system_500_error
  • 설계 의도와의 불일치: ARG13000 의 정의 메시지는 클라이언트 입력 오류를 뜻하며, TSLA-1895 설계 문서는 이 코드를 400 으로 명시했으나 런타임 구현은 500 으로 매핑된다
config/error_code/argument.yml:196-197yaml
ARG13000:
  message: Invalid parameter in sort/order
docs/feature/TSLA-1895.md:394text
| 400       | ARG13000  | ES BadRequest (잘못된 query DSL 등) — root_cause reason 전달 |
  • 기대 동작: 매핑되지 않은 정렬 필드는 클라이언트 입력 오류이므로 400(또는 alias 화이트리스트 검증으로 사전 차단)로 응답해야 한다.
  • 실제 동작: Cupix::Errors::Argumentsystem_500_error → 500 서버 에러로 응답 및 Error Tracking 집계.

Log Evidence#

cupixvista-api 가 tesla 임을 확인한 span 조회 (production 스택트레이스가 /var/app/current/app/repositories/base_repository.rb 를 가리킴):

text
service:cupixvista-api status:error
json
{
  "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건이었다. 검색한 쿼리와 결과:

text
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 내 재발 감지용):

text
service:cupixvista-api status:error "in order to sort on"

ARG13000 전체 발생량 (정렬/필터 무매핑 포함):

text
service:cupixvista-api "ARG13000"

Risk Assessment#

  • Risk level: low
  • 예상 복잡도: standard (상태 코드 매핑 변경은 클라이언트 계약 조율 필요)

Noise Verdict#

noise — 매핑되지 않은 정렬 필드라는 클라이언트 입력 검증 실패가 ARG13000 의 status-code 매핑 오류로 500 으로 새는 것일 뿐 서버 코드 결함이 아니므로 noise 로 판정한다.