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
- Confirm the data is actually text; for binary use the raw hex/bytes instead of UTF-8 decoding.
- For ABI string types use the proper solidity decoder (web3.toBigNumber/web3's ABI decode) rather than toAscii.
- Sanitize hex first: pad odd-length strings and strip 0x consistently.
- 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
- Know the field's ABI type before string-decoding.
- Use ABI decoders for string/bytes return values, not raw toAscii.
- Default to hex representation when data type is unknown.
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
- Parsing and encoding errors: unexpected token, malformed input — why parsers reject input and how to find the real culprit.
Related errors
- This unit doesn't exists, please use the one of the followin
- Contract transaction couldn't be found after 50 blocks
- The contract code couldn't be stored, please check your gas
- Cannot send value to non-payable constructor
- Filter ID Error: filter().get() can't be chained synchronous
AI-assisted analysis of ethereum/go-ethereum@6bb0588ad8 (2026-08-15).
Data as JSON: /api/errors/1beb6571dd1a4094.
Report an issue: GitHub.