ClientErrorController::value_too_long_400_error | The length of the input value for the 'meta' colum
RCA: ClientErrorController::value_too_long_400_error | meta column too long
Overview#
What Happened#
2026-04-27 00:33:56 UTC에 cupixworks-api 서비스의 ap-southeast-2 리전에서 POST /api/v1/form_fields/bulk 엔드포인트로 FormField bulk create 요청 시, meta 컬럼에 111,898 바이트 크기의 데이터를 저장하려 하여 MySQL TEXT 타입의 65,535 바이트 제한을 초과했다. ActiveRecord::ValueTooLong 예외가 발생하여 400 응답이 반환되었다.
Quick Facts#
| Field | Value |
|---|---|
| exception.class | ActiveRecord::ValueTooLong |
| exception.message | Mysql2::Error: Data too long for column 'meta' at row 1 |
| top_frame | app/factories/form_field_factory.rb:32 |
| env | production, ap-southeast-2 |
| deploy | production-ap-southeast-2-20260424T0208Z0-a4578cc0-cupixworks |
Affected Teams#
| Team / Domain | Error Count | Impact |
|---|---|---|
| endeavourgroup (team_id: 180) | 10건 (7일간) | form field 생성 실패, 사용자가 대용량 meta 데이터를 포함한 form field를 저장할 수 없음 |
Timeline#
- 2026-04-24 06:22:46Z -- 동일 사용자(jonathan.tulloch@cupix.com)가 최초로
POST /api/v1/form_fields단건 create에서 동일 에러 발생 (Cupix::Errors::Parameter로 처리) - 2026-04-26 04:19:34Z ~ 04:42:41Z -- 같은 사용자가 단건 create 시도 6회 연속 실패
- 2026-04-27 00:33:56Z --
POST /api/v1/form_fields/bulkbulk create 시도에서ActiveRecord::ValueTooLong이ClientErrorController까지 전파되어 error 로그 기록됨 (본 클러스터) - 2026-04-27 -- Error Sweeper에 의해 감지 및 RCA 수행
Error Log#
ClientErrorController::value_too_long_400_error | The length of the input value for the 'meta' column is too long (length: 111898).
Impact#
- Service:
cupixworks-api - 발생 횟수: 1 (error 레벨 로그 기준; 동일 원인 400 응답은 7일간 10건)
- 최초 발생: 2026-04-27T00:33:56.967Z
- 최근 발생: 2026-04-27T00:33:56.967Z
Root Cause Summary#
FormFieldFactory#bulk_create_by_sql 메서드가 FormField.new(...).save!를 직접 호출하는데, BaseFactory#create!에 있는 ActiveRecord::ValueTooLong 예외 처리 로직(Cupix::Errors::Parameter로 래핑)을 거치지 않는다. 그 결과 ActiveRecord::ValueTooLong이 컨트롤러 레벨의 rescue_from까지 전파되어 ClientErrorController::value_too_long_400_error에서 잡히고, error 레벨 로그가 기록된다. 단건 create 경로에서는 BaseFactory가 동일 예외를 Cupix::Errors::Parameter로 변환하여 client_400_error 핸들러에서 처리하므로 error 레벨 로그가 발생하지 않는다. 근본적으로는 form_fields 테이블의 meta 컬럼이 MySQL TEXT (65,535 bytes)로 정의되어 있어 111,898 바이트 크기의 데이터를 수용할 수 없다.
Technical Analysis#
Code Path#
1. Entry point -- Api::V1::FormFieldsController#bulk_create
요청은 POST /api/v1/form_fields/bulk으로 들어오며, BulkableController#bulk_create가 처리한다:
def bulk_create
if params[:bulk_type].present? && params[:bulk_type] == 'entity'
raise NotImplementedError
else
created_ids = factory_instance.bulk_create_by_sql(params)
end
render_json 200, created_ids
end
2. Factory -- FormFieldFactory#bulk_create_by_sql
bulk_create_by_sql는 각 form_field 항목에 대해 FormField.new(...).save!를 직접 호출한다:
def bulk_create_by_sql(request)
check_bulk_requests(request)
raise Cupix::Errors::PermissionDenied.new(code: 'PERM10000', reason: 'Permission denied to create `FormField`') unless Pundit.policy(current_user, current_team).create?
new_form_field_ids = []
ActiveRecord::Base.transaction do
new_form_field_ids = request[:form_fields].map do |form_field_item|
form_field = ::FormField.new(form_field_item.permit!.to_hash.merge({
'team_id' => current_team.id,
'user_id' => current_user.id
}))
form_field.save! # <-- ActiveRecord::ValueTooLong 발생 지점
form_field.id
end
end
new_form_field_ids
end
meta 컬럼에 111,898 바이트 데이터가 포함된 상태로 save!가 호출되면, MySQL이 Data too long for column 'meta' 에러를 반환하고 Rails가 이를 ActiveRecord::ValueTooLong으로 래핑한다.
3. Failure point -- 예외 전파 경로의 차이
단건 create 경로에서는 BaseFactory#create!가 ActiveRecord::ValueTooLong을 catch하여 Cupix::Errors::Parameter로 변환한다:
rescue ActiveRecord::ValueTooLong => e
raise Cupix::Errors::Parameter.new(code: 'ARG10001', reason: 'Invalid argument', message: e.message)
이 Cupix::Errors::Parameter는 ClientErrorController의 client_400_error 핸들러(line 14)에서 처리되며, Cupix::Logger.error를 호출하지 않는다.
반면, bulk_create_by_sql는 BaseFactory#create!를 사용하지 않고 save!를 직접 호출하므로, ActiveRecord::ValueTooLong이 그대로 컨트롤러까지 전파된다:
rescue_from ActiveRecord::ValueTooLong, with: :value_too_long_400_error
def value_too_long_400_error(exception)
request_body = request.body.read
column_name = exception.message.match(/for column '(.+?)'/)[1]
value = extract_value(request_body, column_name)
error_message = "The length of the input value for the '#{column_name}' column is too long (length: #{value.length})."
Cupix::Logger.error('ClientErrorController::value_too_long_400_error | ' + error_message)
raise_error(400, exception, code: 'ARG10000', type: Cupix::Errors::Parameter, reason: 'Invalid parameter', message: error_message)
end
이 핸들러에서 Cupix::Logger.error가 호출되어 본 클러스터의 error 로그가 생성된다.
4. 스키마 -- form_fields.meta 컬럼 정의
t.text "meta"
MySQL TEXT 타입은 최대 65,535 바이트이며, 사용자가 전송한 111,898 바이트를 수용할 수 없다. rooms 테이블처럼 size: :medium (MEDIUMTEXT, 16MB)으로 정의되어 있다면 이 에러는 발생하지 않는다.
Log Evidence#
사용한 Datadog 쿼리:
service:cupixworks-api status:error "value_too_long"
service:cupixworks-api "Data too long for column meta"
에러 로그 (application level):
{
"timestamp": "2026-04-27T00:33:56.967Z",
"status": "error",
"message": "ClientErrorController::value_too_long_400_error | The length of the input value for the 'meta' column is too long (length: 111898).",
"host": "ip-10-1-147-81.ap-southeast-2.compute.internal",
"service": "cupixworks-api"
}
상관 Request 로그:
{
"timestamp": "2026-04-27T00:33:57.269Z",
"status": "info",
"message": "[400] POST /api/v1/form_fields/bulk (Api::V1::FormFieldsController#bulk_create)",
"http.method": "POST",
"http.url": "/api/v1/form_fields/bulk",
"http.status_code": 400,
"duration": "67.5ms",
"error.class": "ActiveRecord::ValueTooLong",
"error.message": "Mysql2::Error: Data too long for column 'meta' at row 1",
"user.email": "jonathan.tulloch@cupix.com",
"team": "endeavourgroup",
"team_id": 180
}
7일간 동일 원인 에러 패턴 (10건, 모두 동일 사용자):
service:cupixworks-api "Data too long for column" "meta" status:(error OR warn)
- 2026-04-24: 3건 (단건 create,
Cupix::Errors::Parameter) - 2026-04-26: 6건 (단건 create,
Cupix::Errors::Parameter) - 2026-04-27: 1건 (bulk create,
ActiveRecord::ValueTooLong-> error 로그)
Hypotheses Considered#
| # | Hypothesis | Evidence for | Evidence against | Verdict |
|---|---|---|---|---|
| H1 | form_fields.meta 컬럼이 MySQL TEXT (65KB) 제한이며, 사용자가 111,898 바이트 데이터를 전송하여 ActiveRecord::ValueTooLong 발생 |
db/schema.rb:2281에서 t.text "meta" (TEXT=65,535B), error 로그에 length: 111898 명시, Mysql2::Error: Data too long for column 'meta' 확인 |
-- | Confirmed |
| H2 | bulk_create_by_sql에서 BaseFactory#create!의 예외 처리를 우회하여 error 레벨 로그 발생 |
form_field_factory.rb:32에서 save! 직접 호출, base_factory.rb:132의 ValueTooLong catch 미적용, 단건 create는 Cupix::Errors::Parameter로 처리됨 (7일간 9건은 error 로그 미생성) |
-- | Confirmed |
| H3 | 클라이언트 측 버그로 비정상적으로 큰 meta 데이터를 전송 | 동일 사용자가 7일간 10회 반복 시도, 일반적 form field meta 크기를 크게 초과(111KB) | 클라이언트 요구사항이 정당할 수 있음 (복잡한 form design), 서버가 schema 제한 내에서만 수용 가능 | Inconclusive |
| H4 | Metable concern의 serialization 과정에서 데이터가 불필요하게 팽창 |
metable.rb에서 FlexibleHash serializer 사용 |
FlexibleHash는 JSON 직렬화를 수행하며 데이터 팽창을 유발하지 않음, 요청 본문 자체가 111,898 바이트 |
Rejected |
Fix Recommendation#
즉시 조치 (Critical)#
app/factories/form_field_factory.rb:26-36:bulk_create_by_sql메서드 내save!호출 부분에ActiveRecord::ValueTooLongrescue 추가하여Cupix::Errors::Parameter로 래핑. 이렇게 하면 단건 create와 동일한 에러 처리 경로를 타게 되어 불필요한 error 레벨 로그가 발생하지 않는다.- 에러 로그 레벨을
error에서warn으로 변경하는 것도 고려. 이 에러는 사용자 입력 유효성 검사 실패이므로 서버 에러가 아닌 클라이언트 에러이다.
단기 개선 (1주 이내)#
form_fields테이블의meta컬럼을MEDIUMTEXT(size: :medium)로 마이그레이션하는 것을 검토.rooms테이블은 이미size: :medium을 사용하고 있어 선례가 있다. 다만, 111KB 크기의 form field meta가 정상적인 사용 패턴인지 사용자/제품팀과 확인 필요.BulkableController및 하위 Factory들의bulk_create_by_sql메서드에서 공통적으로ActiveRecord::ValueTooLong을 처리하도록 패턴 통일.
장기 개선 (재발 방지)#
- API 레이어에서 요청 본문 크기에 대한 사전 검증(pre-validation) 로직 추가. 데이터베이스에 도달하기 전에 컬럼별 크기 제한을 체크하여 명확한 에러 메시지를 반환.
ClientErrorController#value_too_long_400_error의 로그 레벨을warn으로 하향 조정 검토. 클라이언트 입력 검증 실패는 서비스 에러가 아닌 예상 가능한 시나리오이다.
Monitoring#
form_fields관련ValueTooLong에러 빈도 모니터링:
service:cupixworks-api "value_too_long_400_error" "form_field"
meta컬럼 크기 초과 에러 전체 모니터링:
service:cupixworks-api "Data too long for column" "meta"
Risk Assessment#
- Risk level: low
- 예상 복잡도: trivial --
bulk_create_by_sql에 rescue 블록 추가 또는 컬럼 타입 마이그레이션