Index error - [400] {"error":{"root_cause":[{"type":"mapper_parsing_exception","reason":"failed to p
RCA: Elasticsearch geo_point mapper_parsing_exception in ElementTrace indexing
Overview#
What Happened#
2026-05-22 04:0004:43 UTC 사이에 90)를 벗어나는 값(예: cupixworks-api 서비스에서 ElementTrace를 Elasticsearch에 인덱싱하는 과정에서 mapper_parsing_exception 에러가 6,356회 발생했다. BIM 좌표계의 값을 geo_point의 latitude/longitude로 직접 사용하면서, 유효 범위(-902139310, -167596)이 Elasticsearch에 전달되어 거부되었다.
Quick Facts#
| Field | Value |
|---|---|
| exception.class | Elasticsearch::Transport::Transport::Errors::BadRequest |
| exception.message | mapper_parsing_exception: failed to parse field [location] of type [geo_point] |
| top_frame | app/models/concerns/searchable.rb:51 (Index error), app/models/concerns/searchable.rb:116 (ElasticsearchError) |
| env | production, us-west-2 |
Timeline#
- 2026-05-22T04:00:01Z — 최초 에러 발생 (ElementTrace._index_document)
- 2026-05-22T04:43:07Z — 마지막 에러 기록
- 2026-05-22T05:00:00Z — Error Sweeper 수집
Error Log#
Index error - [400] {"error":{"root_cause":[{"type":"mapper_parsing_exception","reason":"failed to parse field [location] of type [geo_point]"}],"type":"mapper_parsing_exception","reason":"failed to parse field [location] of type [geo_point]","caused_by":{"type":"illegal_argument_exception","reason":"illegal latitude value [2139310.163528784] for location"}},"status":400}
Impact#
- Service:
cupixworks-api - 발생 횟수: 6,356
- 최초 발생: 2026-05-22T04:00:01.281Z
- 최근 발생: 2026-05-22T04:43:07.973Z
ElementTrace 인덱싱 실패로 인해 해당 element trace들의 Elasticsearch 문서가 생성/갱신되지 않았다. 이는 SQA Editing의 Geo Aggregation 기반 작업 분할(TSLA-10800)에서 해당 element trace들이 누락되어, 작업 바구니(Editing) 할당이 불완전해질 수 있다.
Root Cause Summary#
Properties::Element#bim_center_location 메서드가 BIM 모델의 로컬 좌표(bim_bounds + offset + origin)를 계산하여 { lat: center_y, lon: center_x } 형태로 반환하는데, 이 값에 대한 geo_point 유효 범위 검증이 전혀 없다. BIM 좌표는 밀리미터 또는 미터 단위의 로컬 좌표계(State Plane, UTM 등)를 사용하므로, offset/origin이 큰 모델에서는 수십만수백만 단위의 값이 생성된다. Elasticsearch의 geo_point는 latitude -9090, longitude -180~180만 허용하므로 400 에러로 거부된다.
Technical Analysis#
Code Path#
- Entry point: ElementTrace가 create/update 되면
after_commit콜백에서_index_document또는_update_document가 호출된다.
after_commit on: [:create] do
_index_document
end
after_commit on: [:update] do
_update_document
end
- Serialization:
as_indexed_json에서ElementTraceSerializer를 사용하여 인덱싱할 JSON을 생성한다.
attribute :location do |element_trace|
element_trace.element&.bim_center_location
end
- Failure point:
bim_center_location이 BIM 좌표를 그대로 geo_point 형식으로 반환한다. 범위 검증 없음.
def bim_center_location
return nil if bim_bounds.blank?
return nil unless bim_bounds.is_a?(Array) && bim_bounds.size == 6
x_min, y_min, _z_min, x_max, y_max, _z_max = bim_bounds
center_x = (x_min + x_max) / 2.0
center_y = (y_min + y_max) / 2.0
bim = bim_revision&.bim
if bim.present?
offset = bim.offset || [0, 0, 0]
origin = bim.origin || [0, 0, 0]
center_x += (offset[0] || 0) + (origin[0] || 0)
center_y += (offset[1] || 0) + (origin[1] || 0)
end
{ lat: center_y, lon: center_x }
end
- Error handling: 인덱싱 실패 시
BulkIndexWorker로 재시도를 enqueue한다. 같은 데이터로 재시도하므로 동일 에러가 반복된다.
rescue StandardError => e
Cupix::Logger.error("Index error - #{e.message}", class: self.class.name, function: __method__)
BulkIndexWorker.perform_async(self.class.name, [id], 'index')
end
- Retry amplification:
BulkIndexWorker는retry: 5로 설정되어 있어, 한 번 실패한 인덱싱이 최대 5회 추가 재시도된다. 하지만 데이터 자체가 잘못되어 있으므로 모든 재시도가 실패한다.
sidekiq_options queue: :default, retry: 5
Log Evidence#
Datadog 검색 쿼리:
service:cupixworks-api status:error "mapper_parsing_exception" "illegal latitude"
로그에서 확인된 비정상 latitude 값 패턴 (모두 동일 BIM 모델의 element들로 추정):
{"reason": "illegal latitude value [-167596.0191495257] for location"}
{"reason": "illegal latitude value [-167597.266924526] for location"}
{"reason": "illegal latitude value [-167593.9331745257] for location"}
{"reason": "illegal latitude value [-167595.5047995257] for location"}
{"reason": "illegal latitude value [-167595.8095995257] for location"}
클러스터 대표 에러의 latitude 값:
{"reason": "illegal latitude value [2139310.163528784] for location"}
에러 발생 함수:
_index_document— 새 document 생성 시_update_document— 기존 document 갱신 시
class 태그: ElementTrace (모든 에러가 동일 모델)
Hypotheses Considered#
| # | Hypothesis | Evidence for | Evidence against | Verdict |
|---|---|---|---|---|
| H1 | BIM 좌표가 범위 검증 없이 geo_point로 직접 사용됨 | bim_center_location 코드에 범위 체크 없음 (element.rb:104-121). 로그의 latitude 값이 -167596, +2139310으로 BIM 로컬 좌표계 범위. TSLA-10800 문서에서 "BIM bounds를 geo_point로 변환" 설계 확인 |
— | Confirmed |
| H2 | Elasticsearch 매핑이 잘못 설정되어 coerce: true 없이 strict 모드로 동작 |
ES는 기본적으로 geo_point에 coerce 미적용. 매핑에 coerce: true 없음 (searchable/element_trace.rb:114) |
coerce를 켜도 -90 |
Rejected |
| H3 | 특정 BIM 모델의 offset/origin 데이터가 손상됨 | 로그에서 -167596 근처 값이 반복됨 (동일 BIM 모델의 여러 element) | 설계 문서에서 BIM 좌표를 geo_point로 사용하는 것이 의도된 동작. 좌표가 크다는 것은 대형 건물이나 실좌표 기반 BIM에서 정상적 시나리오 | Rejected |
Fix Recommendation#
즉시 조치 (Critical)#
app/models/concerns/properties/element.rb:104-121의 bim_center_location 메서드에서 반환 전 geo_point 유효 범위를 검증하여, 범위를 벗어나면 nil을 반환하도록 한다.
- 수정 위치:
app/models/concerns/properties/element.rbline 120 (return 직전) - latitude가 -90
90, longitude가 -180180 범위를 벗어나면nil반환 nil반환 시 ES에 location 필드가 저장되지 않으므로 에러가 사라진다
단기 개선 (1주 이내)#
TSLA-10800의 원래 설계 의도를 재검토해야 한다. BIM 로컬 좌표를 geo_point로 사용하는 것은 Geo Aggregation을 위한 편의 구현이었으나, 실좌표 기반 BIM 모델에서는 동작하지 않는다. 두 가지 방향 중 택일:
- 좌표 정규화: BIM 좌표를 -90
90 / -180180 범위로 정규화(normalize)하여 매핑. geohash aggregation의 목적은 "근접 element끼리 그룹핑"이므로, 상대적 위치 관계만 유지되면 된다. - 별도 필드 사용: geo_point 대신
float타입의bim_x,bim_y필드를 사용하고, range query + script 기반 그룹핑으로 전환.
장기 개선 (재발 방지)#
- Searchable concern의
_index_documentrescue 블록에서BulkIndexWorker로 무조건 재시도하는 패턴을 개선. 400 에러(클라이언트 잘못)는 재시도 불필요 — 5xx 에러만 재시도하도록 분기. - ES 인덱싱 serializer에서 geo_point 필드에 대한 공통 validation concern 추가.
Monitoring#
추가할 알림:
service:cupixworks-api status:error "mapper_parsing_exception"
geo_point 관련 인덱싱 실패를 즉시 감지하기 위한 Datadog monitor를 설정한다. threshold: 10회/5분 이상 시 alert.
Risk Assessment#
- Risk level: medium
- 예상 복잡도: standard
데이터 무결성 영향: 해당 element trace들이 ES에 인덱싱되지 않아 Geo Aggregation 기반 Editing 분할에서 누락될 수 있다. 다만 SQA 작업 흐름의 보조 기능(자동 그룹핑)이므로 서비스 전체 가용성에는 영향 없음.