ES /docs

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#

  1. 2026-04-24 06:22:46Z -- 동일 사용자(jonathan.tulloch@cupix.com)가 최초로 POST /api/v1/form_fields 단건 create에서 동일 에러 발생 (Cupix::Errors::Parameter로 처리)
  2. 2026-04-26 04:19:34Z ~ 04:42:41Z -- 같은 사용자가 단건 create 시도 6회 연속 실패
  3. 2026-04-27 00:33:56Z -- POST /api/v1/form_fields/bulk bulk create 시도에서 ActiveRecord::ValueTooLongClientErrorController까지 전파되어 error 로그 기록됨 (본 클러스터)
  4. 2026-04-27 -- Error Sweeper에 의해 감지 및 RCA 수행

Error Log#

Datadog Logs

text
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가 처리한다:

app/controllers/concerns/bulkable_controller.rb:10-18ruby
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!를 직접 호출한다:

app/factories/form_field_factory.rb:20-39ruby
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로 변환한다:

app/factories/base_factory.rb:132-133ruby
rescue ActiveRecord::ValueTooLong => e
  raise Cupix::Errors::Parameter.new(code: 'ARG10001', reason: 'Invalid argument', message: e.message)

Cupix::Errors::ParameterClientErrorControllerclient_400_error 핸들러(line 14)에서 처리되며, Cupix::Logger.error를 호출하지 않는다.

반면, bulk_create_by_sqlBaseFactory#create!를 사용하지 않고 save!를 직접 호출하므로, ActiveRecord::ValueTooLong이 그대로 컨트롤러까지 전파된다:

app/controllers/concerns/client_error_controller.rb:29ruby
rescue_from ActiveRecord::ValueTooLong, with: :value_too_long_400_error
app/controllers/concerns/client_error_controller.rb:45-53ruby
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 컬럼 정의

db/schema.rb:2281ruby
t.text "meta"

MySQL TEXT 타입은 최대 65,535 바이트이며, 사용자가 전송한 111,898 바이트를 수용할 수 없다. rooms 테이블처럼 size: :medium (MEDIUMTEXT, 16MB)으로 정의되어 있다면 이 에러는 발생하지 않는다.

Log Evidence#

사용한 Datadog 쿼리:

text
service:cupixworks-api status:error "value_too_long"
text
service:cupixworks-api "Data too long for column meta"

에러 로그 (application level):

json
{
  "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 로그:

json
{
  "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건, 모두 동일 사용자):

text
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:132ValueTooLong 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::ValueTooLong rescue 추가하여 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 에러 빈도 모니터링:
text
service:cupixworks-api "value_too_long_400_error" "form_field"
  • meta 컬럼 크기 초과 에러 전체 모니터링:
text
service:cupixworks-api "Data too long for column" "meta"

Risk Assessment#

  • Risk level: low
  • 예상 복잡도: trivial -- bulk_create_by_sql에 rescue 블록 추가 또는 컬럼 타입 마이그레이션