private static String buildErrorMessage(final Charset charset,
                                                final byte[] malformedBytes,
                                                final long offset) {
            final String printableStr = HexDumpUtil.decodeAsPrintableChars(
                    malformedBytes,
                    charset,
                    DecodedChar.UNKNOWN_CHAR_REPLACEMENT);

            return "Unable to decode a "
                    + charset.displayName()
                    + " character starting at byte offset " + ModelStringUtil.formatCsv(offset)
                    + ". Showing " + LogUtil.namedCount("byte", malformedBytes.length) + " at this offset: " +
                    "[" + ByteArrayUtils.byteArrayToHex(malformedBytes) + "] as hex, " +
                    "[" + printableStr + "] as characters.";
        }
@return A {@link DecodedChar} representing the character decoded from n bytes supplied by byteSupplier or
null if byteSupplier has no bytes to supply.
@throws DecoderException If it fails to decode a char after consuming MAX_BYTES_PER_CHAR bytes
                         from byteSupplier
stroom-pipeline/src/main/java/stroom/pipeline/reader/ByteStreamDecoder.java