gchq/CyberChef · error · OperationError

Incorrectly Encoded Word

Error message

Incorrectly Encoded Word

What it means

Thrown by the MIME Decoding operation while parsing a Q-encoded encoded word, when a '=' escape appears too close to the end of the word to contain the required two hex digits. RFC 2047 Q-encoding uses '=XX' for a byte value; if the '=' is at a position where fewer than two characters follow it (i + 2 >= length), parseQEncodedWord throws at MIMEDecoding.mjs:152. This indicates a truncated or malformed escape sequence.

Source

Thrown at src/core/operations/MIMEDecoding.mjs:152

            }
        }

        throw new OperationError("Unhandled Charset");
    }

    /**
     * Parses a Q encoded word
     *
     * @param encodedWord
     */
    parseQEncodedWord(encodedWord) {
        let decodedWord = "";
        for (let i = 0; i < encodedWord.length; i++) {
            if (encodedWord[i] === "_") {
                decodedWord += " ";
            // Parse hex encoding
            } else if (encodedWord[i] === "=") {
                if ((i + 2) >= encodedWord.length) throw new OperationError("Incorrectly Encoded Word");
                const decodedHex = Utils.byteArrayToChars(fromHex(encodedWord.substring(i + 1, i + 3)));
                decodedWord += decodedHex;
                i += 2;
            } else if (
                (encodedWord[i].charCodeAt(0) >= " ".charCodeAt(0) && encodedWord[i].charCodeAt(0) <= "~".charCodeAt(0)) ||
                encodedWord[i] === "\n" ||
                encodedWord[i] === "\r" ||
                encodedWord[i] === "\t") {
                decodedWord += encodedWord[i];
            } else {
                throw new OperationError("Incorrectly Encoded Word");
            }
        }

        return decodedWord;
    }
}

View on GitHub (pinned to 4290ea7539)

Solutions

  1. Repair the encoded word so every '=' is followed by exactly two hexadecimal digits (e.g. complete '=2' to '=20', remove a stray trailing '=').
  2. If the header is corrupt beyond repair, strip or replace the malformed encoded word before decoding.
  3. Re-acquire the original message from the source to avoid transport truncation.

Example fix

// before — dangling '=' (incomplete hex escape)
// =?UTF-8?Q?Hello= world?=

// after — complete the escape (=20 is space)
// =?UTF-8?Q?Hello=20world?=
Defensive patterns

Strategy: validation

Validate before calling

// Reject Q-words with a dangling '=' escape before decoding.
function wellFormedQWord(w) {
  for (let i = 0; i < w.length; i++) {
    if (w[i] === '=' && i + 2 >= w.length) return false;
  }
  return true;
}
if (!wellFormedQWord(text)) {
  // repair: pad/complete the escape, or strip the malformed word
}

Type guard

function isWellFormedQWord(v: unknown): v is string {
  if (typeof v !== 'string') return false;
  for (let i = 0; i < v.length; i++) {
    if (v[i] === '=' && i + 2 >= v.length) return false;
  }
  return true;
}

Try / catch

try {
  mimeDecoding.run(bytes, []);
} catch (e) {
  if (e instanceof OperationError && /Incorrectly Encoded Word/.test(e.message)) {
    // strip or repair the malformed encoded word, then retry
  } else throw e;
}

Prevention

When it happens

Trigger: A Q-encoded word ending in a dangling '=', e.g. =?UTF-8?Q?abc= ?=, =?UTF-8?Q?ab=A?=, or =?UTF-8?Q?x=4?= — any case where '=' is not followed by exactly two hex digits before the closing '?='. Raised at MIMEDecoding.mjs:152.

Common situations: Headers truncated by a line-wrap/transport issue; a malformed '=' introduced by mis-escaping; copy/paste that chopped the end of the encoded word; an encoder bug that emitted an incomplete escape.

Related errors


AI-assisted analysis of gchq/CyberChef@4290ea7539 (2026-08-13). Data as JSON: /api/errors/49b566a8b2bce03a. Report an issue: GitHub.