sentry-ruby icon indicating copy to clipboard operation
sentry-ruby copied to clipboard

exception happened in background worker: source sequence is illegal/malformed utf-8

Open grosser opened this issue 1 month ago • 5 comments

Issue Description

Something fails in production and all I see in the logs is this message, which is not helpful since I need the original backtrace and error message to begin debugging

Reproduction Steps

raise an error that includes invalid utf8

Expected Behavior

<?> icons replace invalid utf8

Actual Behavior

error not sent to sentry and log shows message

Ruby Version

3.4.6

SDK Version

5.28.0

Integration and Its Version

none

Sentry Config

nothing special, except a custom logger that does {message: message}.to_json

grosser avatar Dec 02 '25 01:12 grosser

RUBY-123

linear[bot] avatar Dec 02 '25 01:12 linear[bot]

@grosser thanks for the report. Any chance you could give me an example message that causes this? We do have handling of malformed utf-8 strings in place.

solnic avatar Dec 09 '25 14:12 solnic

sadly did not find more info and don't have a way to reliably reproduce it feel free to close if you don't see any obvious spot where this could have slipped through

grosser avatar Dec 09 '25 19:12 grosser

@grosser alright, I'll dig into it - could you tell me what exact custom logger do you use that does {message: message}.to_json?

solnic avatar Dec 10 '25 11:12 solnic

standard logger with a formatter that does:

def call(level, _, _, m)
  message = {message: m.message, backtrace: m.backtrace.first(5).join("\n")} if m.is_a?(Exception)
  message = {message: m} if m.is_a?(String)
  {severity: level, worker: @worker}.merge(message).to_json << "\n"
end

grosser avatar Dec 13 '25 01:12 grosser

@grosser how exactly do you configure this logger in Sentry config?

solnic avatar Dec 15 '25 15:12 solnic

class JsonLogger
  def call(level, _, _, m)
    message = m
    message = {message: m.message, backtrace: m.backtrace.first(5).join("\n")} if m.is_a?(Exception)
    message = {message: m} if m.is_a?(String)
    {severity: level}.merge(message).to_json << "\n"
  end

  def self.build(out)
    logger = Logger.new(out, level: Logger::INFO)
    logger.formatter = new
    logger
  end
end

Sentry.init do |config|
  config.sdk_logger = JsonLogger.build($stdout)
  ...
end

grosser avatar Dec 16 '25 02:12 grosser