Invalid location format: lon
RCA: Invalid location format: lon
Overview#
What Happened#
2026-07-14 20:46 KST 프로덕션 cupixworks-api 에서 Facility#set_parameters 처리 중 params[:location] 이 JSON 객체가 아닌 문자열 "lon" 으로 들어왔다. JSON.parse("lon") 이 JSON::ParserError 를 발생시켰고 코드가 이를 error 레벨로 로깅한 뒤 그대로 재발생시켰다. 발생 건수는 1건이며 tenant cupix, region us-west-2 에서 관측됐다.
Quick Facts#
| Field | Value |
|---|---|
| exception.class | JSON::ParserError |
| exception.message | Invalid location format: lon |
| top_frame | app/concerns/parameter.rb:56-59 |
| env | production, us-west-2 |
Affected Teams#
| Team / Domain | Error Count | Impact |
|---|---|---|
| cupixworks-api / Facility update | 1 | Facility update 요청 1건 실패, 클라이언트 500 응답 (unhandled JSON::ParserError 는 controller 에 rescue_from 이 없음) |
Timeline#
- 2026-07-14 20:46:05 KST —
Facility#set_parameters진입,params[:location] = "lon"(String) - 2026-07-14 20:46:05 KST —
JSON.parse("lon")이JSON::ParserError발생 - 2026-07-14 20:46:05 KST —
Cupix::Logger.error("Invalid location format: lon", class: "Facility", function: "set_parameters", module: "Parameter")기록 후raise e - 2026-07-14 20:46:05 KST — error-sweeper collector 가 로그를 수집, cluster
145ece24-ddad-4fbe-9542-99f426fb5ffb생성
Error Log#
Invalid location format: lon
Impact#
- Service:
cupixworks-api - 발생 횟수: 1
- 최초 발생: 2026-07-14 20:46 KST
- 최근 발생: 2026-07-14 20:46 KST
블래스트 반경은 좁다. 최근 24시간 검색에서 동일 메시지가 1건만 존재하고, 다른 tenant/region 확산 흔적이 없다. 클라이언트가 잘못된 location 페이로드("lon" 문자열)를 한 번 보낸 결과로 판단된다.
Root Cause Summary#
클라이언트가 Facility update 요청에 location 파라미터로 JSON 객체 문자열(예: {"lat":37.5,"lon":127.0}) 대신 리터럴 문자열 "lon" 을 전달했다. Parameter#set_parameters 는 params[:location] 이 String 인 경우 JSON.parse 로 파싱을 시도하는데, "lon" 은 유효한 JSON 이 아니므로 JSON::ParserError 가 발생한다. 코드는 이 예외를 error 레벨로 로깅한 뒤 그대로 재발생시키고, Api::V1::FacilitiesController 를 포함한 어떤 controller 에도 rescue_from JSON::ParserError 가 정의돼 있지 않아 미포착 예외로 처리돼 500 응답을 유발한다. 즉 원인은 클라이언트의 잘못된 입력이지만, 서버가 이를 400 Bad Request 가 아닌 500 server error 로 취급하고 error 레벨 로그를 남기는 것이 결함이다.
Technical Analysis#
Code Path#
- Entry point:
app/controllers/api/v1/facilities_controller.rb:125-129(FacilitiesController#update→repository_instance.update(params)) - 파라미터 처리 진입:
app/concerns/parameter/facility.rb:14-18(Parameter::Facility#set_parameters→super로 상위Parameter#set_parameters호출) - Failure point:
app/concerns/parameter.rb:53-60—params[:location]이 String 인 경우JSON.parse호출
Controller 진입:
def update
@model = repository_instance.update(params)
super
end
파싱 실패 지점:
if params[:location].present? && @model.respond_to?(:location)
if params[:location].is_a?(String)
begin
location = JSON.parse(params[:location])
rescue => e
Cupix::Logger.error("Invalid location format: #{params[:location]}", class: @model.class.name, function: __method__, module: 'Parameter')
raise e
end
else
location = params[:location]
end
if location['lat'].present? || location[:lat].present?
@model.latitude = location['lat'] || location[:lat]
end
if location['lon'].present? || location[:lon].present?
@model.longitude = location['lon'] || location[:lon]
end
end
기대 동작: params[:location] 은 {"lat": <float>, "lon": <float>} 형태의 JSON 문자열이거나 Hash. JSON.parse 결과에서 lat/lon 을 추출해 모델에 설정.
실제 동작: params[:location] == "lon" (문자열 리터럴). JSON.parse("lon") 이 유효한 JSON 이 아니므로 JSON::ParserError 발생. 코드는 error 레벨로 로깅하고 그대로 re-raise.
Controller 계층에서의 재처리 부재:
rescue_from ActionController::ParameterMissing,
ActiveRecord::RecordInvalid, with: :invalid_parameter_400_error
JSON::ParserError 는 ClientErrorController 의 rescue_from 목록에 없고, ServerErrorController 에도 없다. Ruby 기본 예외 계층상 JSON::ParserError 는 StandardError 를 상속하지만 위의 어떤 매칭에도 걸리지 않으므로 Rails 의 기본 500 응답 경로를 탄다. 이는 참고로 ActionController::ParameterMissing 이 400 으로 매핑되는 것과 대조된다.
동일 파일 내 다른 필드는 JSON::ParserError 를 별도로 처리하지만 location 은 그렇지 않다:
rescue JSON::ParserError => e
즉 프로젝트 전반의 컨벤션은 JSON::ParserError 를 잡아 Cupix::Errors::Parameter (→ 400) 로 재발생하는 것이나, parameter.rb 의 location 블록은 rescue 를 rescue => e 로 광범위하게 잡아 error 로그 후 원본 예외를 그대로 던진다.
Log Evidence#
사용한 Datadog 쿼리 (클러스터 파일 링크 그대로):
service:cupixworks-api status:error @environment:production "Invalid location format: lon"
시간 창: 2026-07-14 20:46 ~ 22:47 KST (URL 기준 from_ts=1784025960000 to_ts=1784033220000).
핵심 로그 항목:
{
"timestamp": "2026-07-14 20:46:05",
"status": "error",
"message": "Invalid location format: lon",
"class": "Facility",
"function": "set_parameters"
}
추가로 넓힌 검색 (service:cupixworks-api "Invalid location format", now-24h) 결과도 위 1건만 반환됐다. 즉 이번 스파이크가 아니라 단발성 이벤트다.
Status board 조회 결과 이 클러스터는 svc:cupixworks-api::unknown 스코프이며 현재 active 인시던트는 없다 (recent 7일 목록에 여러 resolved 인시던트가 있으나 본 클러스터와의 상관관계 없음).
Hypotheses Considered#
| # | Hypothesis | Evidence for | Evidence against | Verdict |
|---|---|---|---|---|
| H1 | 클라이언트가 location 파라미터에 유효하지 않은 JSON 문자열("lon")을 전달했고, Parameter#set_parameters 의 JSON.parse 가 실패해 error 로그 후 재발생 |
로그 메시지가 Invalid location format: lon 이며 parameter.rb:58 의 Cupix::Logger.error("Invalid location format: #{params[:location]}", ...) 템플릿과 정확히 일치. 로그의 class: Facility, function: set_parameters 태그가 parameter.rb:58 의 class: @model.class.name, function: __method__ 와 부합. params[:location] 이 정상 형태였다면 is_a?(String) 분기에서 JSON.parse 가 성공했을 것 ({"lon":...}) 또는 is_a?(String) 이 false 였을 것 |
— | Confirmed |
| H2 | 배포/코드 회귀로 인해 정상 payload 도 파싱에 실패하기 시작함 | 없음 | 24시간 내 동일 메시지 1건. 다른 tenant/region 확산 없음. 최근 parameter.rb 커밋은 TSLA-9920 convert latitude and longitude to Float (2025-06-19) 로 location 파싱 로직 변경 없음 |
Rejected |
| H3 | 특정 다운스트림 서비스(예: 지오코딩 API) 장애로 인해 location 이 잘못 채워짐 | 없음 | 오류는 순수하게 요청 파라미터 파싱 단계에서 발생하며 외부 호출 없음. parameter.rb:56 는 로컬 JSON.parse 뿐 |
Rejected |
| H4 | 기존 s3/es dependency 인시던트의 파생 | Status board 에 최근 svc:cupixworks-api::unknown 인시던트 다수 존재 | 본 클러스터 발생 시각(2026-07-14 20:46 KST) 에 active dep:* 인시던트 없음. recent svc:* 인시던트는 모두 다른 클러스터 세트 | Rejected |
Fix Recommendation#
즉시 조치 (Critical)#
app/concerns/parameter.rb:53-63의location파싱 블록에서 rescue 를JSON::ParserError로 좁히고, 재발생 예외를 클라이언트 오류로 매핑되는Cupix::Errors::Parameter로 변환한다. 프로젝트의 다른 모듈이 이미 이 컨벤션을 따른다 —app/concerns/parameter/annotation.rb:140,app/concerns/parameter/bim.rb:98,app/concerns/parameter/review.rb:25,app/concerns.parameter.rb:180-181의parse_to_json헬퍼가 동일한 패턴을 보여준다.- 로그 레벨을
error→warn으로 낮춘다. 잘못된 클라이언트 입력은 서버 결함이 아니며 error 알림/on-call 노이즈를 유발한다. 메모리의 원칙 "Assess error severity during RCA" 및 "Scope warn-level downgrades to the specific exception class" 를 준수해,rescue JSON::ParserError만 warn 으로 낮추고 상위 예외는 유지한다. - 파일 위치:
app/concerns/parameter.rb:53-63
단기 개선 (1주 이내)#
parameter.rb의parse_to_json(app/concerns/parameter.rb:165-182) 헬퍼를location블록에도 재사용해 파싱 로직을 통일한다. 현재parse_to_json은 파싱 실패 시Cupix::Errors::Parameter를 발생시켜 400 으로 매핑되도록 이미 설계되어 있다.- Controller 계층에서
JSON::ParserError에 대한 안전망을 추가 (ClientErrorController#invalid_parameter_400_error목록에 포함) — 개별 concern 이 rescue 를 누락하더라도 400 이 보장되도록.
장기 개선 (재발 방지)#
- Facility update 파라미터 스키마 검증을 Strong Parameter + JSON schema/
dry-schema등으로 상단 계층에서 수행.location필드는{lat: Float, lon: Float}로 정형화해 문자열 파싱을 근본적으로 제거한다. - API 명세(cupix-api specs)에
location필드 타입을 명시하고 SDK/문서로 클라이언트 오사용을 예방한다.
Monitoring#
Datadog dashboard timeseries widget 에 붙일 수 있는 쿼리 (writing-datadog-monitoring-queries 규칙 준수 — pipe/stats/count by(...) 미사용):
service:cupixworks-api status:error "Invalid location format"
service:cupixworks-api @class:Facility @function:set_parameters status:error
- 위 쿼리로 24시간/7일 발생 추이를 모니터링한다. 반복적으로 튀면(예: 시간당 5건 이상) 특정 클라이언트/버전이 잘못된 payload 를 보내고 있을 가능성을 조사한다.
- 즉시 조치 후에는 위 로그가
status:warn으로 이동하므로 error 카운트는 0 이어야 한다:
service:cupixworks-api status:error "Invalid location format"
Risk Assessment#
- Risk level: low
- 예상 복잡도: trivial
단발성 클라이언트 입력 오류이며 서비스 전반 영향 없음. 코드 수정 범위는 parameter.rb 내 몇 줄에 국한되고, 프로젝트 내 다수 유사 사례(annotation.rb, bim.rb, review.rb) 가 이미 동일 컨벤션을 채택하고 있어 회귀 위험이 낮다.