ActiveModel::MissingAttributeError: missing attribute 'origin_x' for Building
RCA: ActiveModel::MissingAttributeError: missing attribute 'origin_x' for Building
Overview#
What Happened#
2026-08-06 롤링 배포 진행 중(production, us-west-2) GET /api/v1/buildings/{id} (Api::V1::BuildingsController#show) 요청이 약 30분 동안 HTTP 500 을 반환했다. BuildingSerializer 가 record.origin_x 를 읽는 순간, 해당 요청을 처리한 일부 앱 인스턴스의 Building 모델이 origin_x 컬럼을 인식하지 못해 ActiveModel::MissingAttributeError 또는 NoMethodError 가 발생했다. 배포가 끝난 뒤(14:42 KST 이후) 에러는 저절로 사라졌고 #index 요청은 정상 200 을 반환했다.
Quick Facts#
| Field | Value |
|---|---|
| exception.class | ActiveModel::MissingAttributeError (+ 동시 발생 NoMethodError) |
| exception.message | missing attribute 'origin_x' for Building / undefined method 'origin_x' for an instance of Building |
| top_frame | app/serializers/building_serializer.rb:16 |
| endpoint | GET /api/v1/buildings/{id} (Api::V1::BuildingsController#show) |
| deploy | version:production-us-west-2-20260806t0214z... / t0341z... / t0525z... (SHA c1c2bbd4, 롤링 중) |
| env | production, us-west-2 |
Affected Teams#
| Team / Domain | Error Count | Impact |
|---|---|---|
| production us-west-2 (buildings 48/58/59) | 14 (ET occurrence) / 21 (log line, 중복 포함) | 배포 창(window) 동안 특정 building 상세 조회 500, 배포 완료 후 자동 회복 |
Timeline#
- 2026-08-06 14:11 KST —
GET /api/v1/buildings/59부터 500 급증 시작 (배포 창 진입) - 2026-08-06 14:11–14:42 KST — buildings 48/58/59 에 대해
MissingAttributeError와NoMethodError가 번갈아 발생 (ET first_seen 05:11:51Z ~ last_seen 05:42:15Z UTC) - 2026-08-06 14:42 KST — 마지막 500 발생 (
GET /api/v1/buildings/48) - 2026-08-06 14:56 KST 이후 —
GET /api/v1/buildings(#index) 정상 200 반환, 500 재발 없음 → 배포 완료로 자연 회복
Error Log#
missing attribute 'origin_x' for Building
Impact#
- Service:
cupixworks-api - 발생 횟수: 14
- 최초 발생: 2026-08-06 14:11 KST
- 최근 발생: 2026-08-06 14:42 KST
Root Cause Summary#
이 에러는 Building 데이터 결함이나 BuildingSerializer 코드 결함이 아니라, 롤링 배포 창 동안 발생한 schema/attribute 인식 불일치(transient) 이다. origin_x 컬럼은 create_buildings 마이그레이션(db/migrate/20260206002112_create_buildings.rb:16)의 일부로 이미 production buildings 테이블에 존재하고, db/schema.rb:916 에도 반영되어 있다. 그러나 2026-08-06 배포가 롤링으로 진행되는 동안(같은 SHA c1c2bbd4, version 태그 timestamp 가 0214z → 0341z → 0525z 로 여러 개) 요청을 처리한 일부 앱 인스턴스의 Building 모델이 origin_x 를 알지 못하는 상태였다. Rails 는 부팅 시 실제 DB 컬럼으로부터 attribute 접근 메서드를 생성하므로, 컬럼 인식이 되지 않은 인스턴스에서는 record.origin_x 호출이 NoMethodError: undefined method 'origin_x'(메서드 자체가 정의되지 않음) 로, 쿼리 결과에 컬럼이 없는 경우에는 ActiveModel::MissingAttributeError: missing attribute 'origin_x' 로 표면화된다. 동일 시각에 두 예외가 번갈아 나온 것과, 배포 완료 후 즉시 재발이 멈춘 점이 이 진단을 뒷받침한다. BuildingSerializer 는 정상적으로 컬럼을 읽는 코드이며 수정이 필요 없다.
Technical Analysis#
Code Path#
- Entry point:
app/controllers/api/v1/buildings_controller.rb:39-41—set_building→repository_instance.show(params[:id])
def set_building
@model = repository_instance.show(params[:id])
end
- 조회 쿼리:
app/repositories/base_repository.rb:337—permission_joins(default_joins(current_class), current_user).where(attrs).BuildingRepository.default_joins는buildings.*를 select 하므로(app/repositories/building_repository.rb:29-31) 정상 상태에서는origin_x를 포함한 전체 컬럼이 로드된다.
def self.default_joins(record)
record.joins(:team).select('buildings.*')
end
- Failure point:
app/serializers/building_serializer.rb:15-17— 직렬화 단계에서record.origin_x를 읽는 순간 예외 발생. 컬럼을 인식하지 못하는 인스턴스에서는 이 호출이NoMethodError(attribute 메서드 미정의) 또는MissingAttributeError(결과셋에 컬럼 없음) 로 이어진다.
attribute :origin_x do |record|
record.origin_x&.to_f
end
- 참고:
origin_x는 신규 도입 컬럼이 아니라buildings테이블 생성 시점부터 정의된 좌표 컬럼이다.
# Coordinates for site-level placement
t.decimal :origin_x, precision: 20, scale: 10
t.decimal :origin_y, precision: 20, scale: 10
t.decimal :origin_z, precision: 20, scale: 10
t.decimal :bearing, precision: 10, scale: 6
- 기대 동작: 배포된 모든 인스턴스가
origin_x를 포함한buildingsschema 를 인식 → serializer 가 정상적으로 값을 직렬화. - 실제 동작: 롤링 배포 창 동안 일부 인스턴스가
origin_x를 인식하지 못해 serializer 호출 시 예외 → HTTP 500.
Log Evidence#
Datadog 쿼리 (재현 가능):
service:cupixworks-api "buildings" "[500]"
핵심 로그 — 동일 시각에 MissingAttributeError 와 NoMethodError 가 함께 발생(같은 building 48):
{
"timestamp": "2026-08-06 14:42:15",
"status": "info",
"message": "[500] GET /api/v1/buildings/48 (Api::V1::BuildingsController#show)",
"error": ["ActiveModel::MissingAttributeError", "missing attribute 'origin_x' for Building"]
}
{
"timestamp": "2026-08-06 14:42:14",
"status": "info",
"message": "[500] GET /api/v1/buildings/48 (Api::V1::BuildingsController#show)",
"error": ["NoMethodError", "undefined method `origin_x' for an instance of Building"]
}
배포가 롤링으로 진행 중이었음을 보여주는 version 태그(같은 SHA c1c2bbd4, timestamp 상이):
env:production
environment:production
version:production-us-west-2-20260806t0214z0-c1c2bbd4-cupixworks
version:production-us-west-2-20260806t0341z0-c1c2bbd4-cupixworks
version:production-us-west-2-20260806t0525z0-c1c2bbd4-cupixworks
발생 타임라인(500 로그 라인 count, KST):
14:11:53–14:11:56 buildings/59
14:12:27–14:12:30 buildings/59
14:22:24–14:22:26 buildings/59
14:35:14–14:35:18 buildings/58
14:42:14–14:42:15 buildings/48
(이후 재발 없음)
배포 완료 후 정상화 확인:
service:cupixworks-api "GET /api/v1/buildings" "[200]"
{
"timestamp": "2026-08-06 14:58:02",
"status": "info",
"message": "[200] GET /api/v1/buildings (Api::V1::BuildingsController#index)"
}
Hypotheses Considered#
| # | Hypothesis | Evidence for | Evidence against | Verdict |
|---|---|---|---|---|
| H1 | 롤링 배포 창 동안 일부 인스턴스가 origin_x 컬럼을 인식하지 못한 transient schema/attribute 불일치 |
에러가 배포 창(14:11–14:42 KST)에만 집중, 완료 후 재발 0; version 태그가 같은 SHA 로 여러 timestamp(0214z/0341z/0525z) = 롤링 진행 중; 동일 시각에 MissingAttributeError(결과셋 컬럼 없음)와 NoMethodError(attribute 메서드 미정의)가 공존 = schema 인식 문제의 전형 |
— | Confirmed |
| H2 | BuildingSerializer 코드 결함 (잘못된 attribute 참조) |
serializer 가 origin_x 를 직접 참조 |
origin_x 는 create_buildings 마이그레이션 및 db/schema.rb:916 에 정상 존재; 배포 완료 후 동일 코드로 200 정상 반환 → 코드 결함 아님 |
Rejected |
| H3 | 특정 building 레코드(48/58/59) 데이터 손상 | 소수 building ID 에 집중 | 서로 다른 3개 building 에 걸쳐 발생하고, 배포 완료 후 같은 레코드가 정상 조회됨 → 레코드 단위 손상 아님 | Rejected |
| H4 | origin_x 컬럼이 production DB 에 아예 없음(마이그레이션 미실행) |
NoMethodError: undefined method 'origin_x' |
컬럼은 buildings 생성 마이그레이션의 일부(2026-02)이며 이미 배포됨; 에러가 영구적이지 않고 배포 완료와 함께 즉시 소멸 → 컬럼 부재가 아니라 인스턴스별 인식 지연 |
Rejected |
| H5 | permission_joins 의 GROUP BY id + 축약 select 로 origin_x 미로딩 |
permission_joins 가 .group('id').select(...) 수행 |
default_joins 가 buildings.* 를 먼저 select 하고 AR .select 는 누적되므로 정상 상태에선 origin_x 포함; 상시 발생이 아니라 배포 창 한정 → 쿼리 구조 문제 아님 |
Rejected |
Fix Recommendation#
즉시 조치 (Critical)#
- 코드 변경 불필요.
BuildingSerializer와BuildingRepository는 정상이며origin_x컬럼도 이미 존재한다. 에러는 배포 완료와 함께 이미 해소되었다(14:42 KST 이후 재발 0). Error Tracking 이슈는 ignore 처리 권장.
단기 개선 (1주 이내)#
- 배포 절차 점검: DB 마이그레이션과 코드 롤아웃의 순서/타이밍을 확인한다.
.platform/hooks/에는 DB 마이그레이션 단계가 없고(postdeploy/50_init_tesla.sh:11는es:migrate뿐) 마이그레이션이 배포와 분리되어 실행되므로, 롤링 중 신구 인스턴스가 서로 다른 schema 인식 상태로 공존할 수 있다. 배포 시 신규 인스턴스가 트래픽을 받기 전에 schema 를 확실히 인식하도록(warmup 또는 connection schema reload) 절차를 보강한다. - 재발 시 빠른 판별을 위해 배포 window 와 에러 급증의 상관관계를 대시보드에 노출한다(아래 Monitoring).
장기 개선 (재발 방지)#
- 컬럼 추가/스키마 변경을 동반하는 배포에서 "expand → deploy → contract" 패턴을 적용해 신구 코드가 동일 schema 를 안전하게 공유하도록 한다.
- 롤링 배포 중 신규 인스턴스가 health check 통과 후에도 attribute/schema 캐시를 강제 reload 하도록 부팅 시퀀스를 검토한다.
Monitoring#
- buildings 엔드포인트 500 추이(배포 창 상관 확인용):
service:cupixworks-api "GET /api/v1/buildings" "[500]"
origin_x인식 실패 예외 발생 여부:
service:cupixworks-api "origin_x" ("MissingAttributeError" OR "NoMethodError")
Risk Assessment#
- Risk level: low
- 예상 복잡도: trivial (코드 변경 없음, 배포 절차 관점의 운영 개선)
Noise Verdict#
noise — origin_x 컬럼은 이미 존재하고 코드도 정상이며, 에러는 2026-08-06 롤링 배포 창 동안의 일시적 schema 인식 불일치로 배포 완료와 함께 자동 소멸했으므로 코드 수정이 필요 없는 transient 배포 아티팩트입니다.