{"record":{"id":"6e897739b746885e","repo":"elastic/elasticsearch","slug":"input-does-not-start-with-smile-format-header","errorCode":null,"errorMessage":"Input does not start with Smile format header","messagePattern":"Input does not start with Smile format header","errorType":"validation","errorClass":"XContentParseException","httpStatus":null,"severity":"error","filePath":"libs/x-content/impl/src/main/java/org/elasticsearch/xcontent/provider/smile/SmileXContentImpl.java","lineNumber":124,"sourceCode":"\n    @Override\n    public XContentParser createParser(XContentParserConfiguration config, InputStream is) throws IOException {\n        return new SmileXContentParser(config, smileFactory.createParser(validateSmileHeader(is)));\n    }\n\n    private static InputStream validateSmileHeader(InputStream is) throws IOException {\n        PushbackInputStream input = new PushbackInputStream(is, 3);\n        byte[] header = new byte[3];\n        int length = input.readNBytes(header, 0, header.length);\n        input.unread(header, 0, length);\n        if (length == 0) {\n            return input;\n        }\n        if (length < 3\n            || header[0] != SmileConstants.HEADER_BYTE_1\n            || header[1] != SmileConstants.HEADER_BYTE_2\n            || header[2] != SmileConstants.HEADER_BYTE_3) {\n            throw new XContentParseException(null, \"Input does not start with Smile format header\");\n        }\n        return input;\n    }\n\n    @Override\n    public XContentParser createParser(XContentParserConfiguration config, byte[] data, int offset, int length) throws IOException {\n        try {\n            return new SmileXContentParser(config, smileFactory.createParser(data, offset, length));\n        } catch (JsonParseException e) {\n            throw new XContentParseException(null, e.getMessage(), e);\n        }\n    }\n\n    @Override\n    public XContentParser createParser(XContentParserConfiguration config, Reader reader) throws IOException {\n        return new SmileXContentParser(config, smileFactory.createParser(reader));\n    }\n}","sourceCodeStart":106,"sourceCodeEnd":142,"githubUrl":"https://github.com/elastic/elasticsearch/blob/db6a809a667c081ca1dc7500389d26975573215f/libs/x-content/impl/src/main/java/org/elasticsearch/xcontent/provider/smile/SmileXContentImpl.java#L106-L142","documentation":"Thrown by SmileXContentImpl.validateSmileHeader when a parser is created from an InputStream whose first three bytes do not match the Smile binary format magic header (HEADER_BYTE_1/2/3 = 0x3A 0x29 0x0A, i.e. ':)\\n'). The check is skipped only when the stream is entirely empty (length==0). This guards the InputStream overload; the byte[] overload delegates header checking to Jackson's smileFactory.","triggerScenarios":"Calling XContentType.SMILE.xContent().createParser(config, inputStream) where the stream contains JSON, CBOR, YAML, plain text, or any non-Smile bytes. Also triggered when a content-type sniffing layer picks Smile incorrectly and feeds the wrong bytes, or when a Smile stream is double-decompressed/garbled so the first three bytes are wrong.","commonSituations":"Mistaking the xcontent type during manual deserialization (e.g. indexing Smile-encoded docs but reading them back as JSON). Content-Type negotiation bugs in REST handlers that map a JSON body to the Smile parser. Tests that hard-code Smile but supply JSON fixtures. Network/proxy corruption that strips or re-encodes the leading bytes.","solutions":["Confirm the bytes are actually Smile: the stream must begin with 0x3A 0x29 0x0A. If you have JSON/CBOR/YAML, select that XContentType instead of SMILE.","If the content type is unknown, detect it first via XContentType.xContentType(mediaType) or by sniffing the first bytes, then route to the matching createParser.","When reading from an index/store that may have been written in a different format, verify the stored source contentType metadata rather than assuming Smile.","Re-acquire the stream from its origin if it may have been consumed or transformed by an intervening filter (gzip, base64) before reaching the parser."],"exampleFix":"// before\nXContentParser p = XContentType.SMILE.xContent().createParser(config, in); // in holds JSON\n\n// after\nXContentType type = XContentType.xContentType(mediaType); // resolve from header/metadata\ntry (XContentParser p = type.xContent().createParser(config, in)) { ... }","handlingStrategy":"validation","validationCode":"byte[] head = is.readNBytes(3); // peek (or use PushbackInputStream)\nboolean looksSmile = head.length >= 3 && (head[0] & 0xFF) == 0x3A && (head[1] & 0xFF) == 0x29 && (head[2] & 0xFF) == 0x0A;\nif (!looksSmile) { /* pick correct XContentType instead of SMILE */ }","typeGuard":null,"tryCatchPattern":"try (XContentParser p = XContentType.SMILE.xContent().createParser(config, in)) {\n    ...\n} catch (XContentParseException e) {\n    if (e.getMessage().contains(\"Smile format header\")) {\n        // re-detect content type and retry with the correct xContent\n    }\n}","preventionTips":["Always resolve XContentType from the source's media type or by sniffing bytes before selecting a parser.","Use the cluster's content-type detection helpers rather than hard-coding SMILE.","In tests, assert the first three bytes when loading Smile fixtures so silent encoding drift fails early."],"tags":["xcontent","smile","deserialization","header-validation"],"backgroundTag":null,"analyzedSha":"db6a809a667c081ca1dc7500389d26975573215f","analyzedAt":"2026-08-12T01:39:14.192Z","schemaVersion":2},"datasetVersion":"2026-08-12T12:31:55.035Z"}