ethereum/go-ethereum · warning · Error

Malformed UTF-8 data

Error message

Malformed UTF-8 data

What it means

CryptoJS's Utf8 stringify first Latin1-decodes the WordArray bytes, then runs them through decodeURIComponent(escape(...)) to produce UTF-8 text. If the byte sequence is not valid UTF-8, decodeURIComponent throws and it is rethrown as 'Malformed UTF-8 data'. In web3 this surfaces when hex/bytes that are not valid UTF-8 are decoded as a UTF-8 string (e.g. web3.toAscii / hexToString on arbitrary binary).

Source

Thrown at internal/jsre/deps/web3.js:8015

	    var Utf8 = C_enc.Utf8 = {
	        /**
	         * Converts a word array to a UTF-8 string.
	         *
	         * @param {WordArray} wordArray The word array.
	         *
	         * @return {string} The UTF-8 string.
	         *
	         * @static
	         *
	         * @example
	         *
	         *     var utf8String = CryptoJS.enc.Utf8.stringify(wordArray);
	         */
	        stringify: function (wordArray) {
	            try {
	                return decodeURIComponent(escape(Latin1.stringify(wordArray)));
	            } catch (e) {
	                throw new Error('Malformed UTF-8 data');
	            }
	        },

	        /**
	         * Converts a UTF-8 string to a word array.
	         *
	         * @param {string} utf8Str The UTF-8 string.
	         *
	         * @return {WordArray} The word array.
	         *
	         * @static
	         *
	         * @example
	         *
	         *     var wordArray = CryptoJS.enc.Utf8.parse(utf8String);
	         */
	        parse: function (utf8Str) {
	            return Latin1.parse(unescape(encodeURIComponent(utf8Str)));

View on GitHub (pinned to 6bb0588ad8)

Solutions

  1. Confirm the data is actually text; for binary use the raw hex/bytes instead of UTF-8 decoding.
  2. For ABI string types use the proper solidity decoder (web3.toBigNumber/web3's ABI decode) rather than toAscii.
  3. Sanitize hex first: pad odd-length strings and strip 0x consistently.
  4. Catch the error and fall back to a hex representation for display.

Example fix

// before
var s = web3.toUtf8(txInputHex); // throws on non-UTF-8 bytes

// after
var s;
try { s = web3.toUtf8(txInputHex); }
catch (e) { s = txInputHex; } // keep hex form for binary data
Defensive patterns

Strategy: try-catch

Validate before calling

function looksLikeUtf8(hex) {
  var s = hex.replace(/^0x/, '');
  if (s.length % 2 !== 0) return false;
  // crude check: reject control-heavy byte soup
  var bytes = s.match(/.{2}/g).map(function (b) { return parseInt(b, 16); });
  return bytes.filter(function (b) { return b < 0x09 || (b > 0x0d && b < 0x20); }).length === 0;
}

Try / catch

function decodeMaybeUtf8(hex) {
  try { return web3.toUtf8(hex); }
  catch (e) {
    if (e.message === 'Malformed UTF-8 data') return hex; // binary payload
    throw e;
  }
}

Prevention

When it happens

Trigger: Calling string decoding on data whose bytes are not valid UTF-8: raw contract return bytes, a hex string with odd length decoded through the Latin1 path, or ciphertext/random bytes fed to Utf8.stringify. Any invalid multi-byte sequence (e.g. 0x80-0xBF leading byte or truncated 0xC3 sequence) throws.

Common situations: Using web3.toAscii/toUtf8 on ABI-encoded return data, event data fields, or tx input that contains binary (hashes, addresses) rather than text; packing bugs producing odd-length hex.

Understand the failure class

Related errors


AI-assisted analysis of ethereum/go-ethereum@6bb0588ad8 (2026-08-15). Data as JSON: /api/errors/1beb6571dd1a4094. Report an issue: GitHub.