{"record":{"id":"3562d15dff172509","repo":"elastic/elasticsearch","slug":"vector-dimensions-incompatible-x","errorCode":null,"errorMessage":"vector dimensions incompatible: {}!= {} x {}","messagePattern":"vector dimensions incompatible: (.+?)!= (.+?) x (.+?)","errorType":"validation","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"libs/simdvec/src/main/java/org/elasticsearch/simdvec/ESVectorUtil.java","lineNumber":362,"sourceCode":"    /**\n     * Bulk computation of cosine similarity from a byte query vector to four byte candidate vectors.\n     */\n    public static void cosineBulk(byte[] q, byte[] v0, byte[] v1, byte[] v2, byte[] v3, int distancesOffset, float[] distances) {\n        if (q.length != v0.length || q.length != v1.length || q.length != v2.length || q.length != v3.length) {\n            throw new IllegalArgumentException(\"vector dimensions incompatible\");\n        }\n        if (distances.length < 4) {\n            throw new IllegalArgumentException(\"distances array must have length >= 4, but was: \" + distances.length);\n        }\n        if (distancesOffset < 0 || distancesOffset > distances.length - 4) {\n            throw new IllegalArgumentException(\"distancesOffset must be between 0 and distances.length - 4\");\n        }\n        IMPL.cosineBulk(q, v0, v1, v2, v3, distancesOffset, distances);\n    }\n\n    public static long ipByteBinByte(byte[] q, byte[] d) {\n        if (q.length != d.length * B_QUERY) {\n            throw new IllegalArgumentException(\"vector dimensions incompatible: \" + q.length + \"!= \" + B_QUERY + \" x \" + d.length);\n        }\n        return IMPL.ipByteBinByte(q, d);\n    }\n\n    /**\n     * Compute the inner product of two vectors, where the query vector is a byte vector and the document vector is a bit vector.\n     * This will return the sum of the query vector values using the document vector as a mask.\n     * When comparing the bits with the bytes, they are done in \"big endian\" order. For example, if the byte vector\n     * is [1, 2, 3, 4, 5, 6, 7, 8] and the bit vector is [0b10000000], the inner product will be 1.0.\n     * @param q the query vector\n     * @param d the document vector\n     * @return the inner product of the two vectors\n     */\n    public static int ipByteBit(byte[] q, byte[] d) {\n        if (q.length != d.length * Byte.SIZE) {\n            throw new IllegalArgumentException(\"vector dimensions incompatible: \" + q.length + \"!= \" + Byte.SIZE + \" x \" + d.length);\n        }\n        return IMPL.ipByteBit(q, d);","sourceCodeStart":344,"sourceCodeEnd":380,"githubUrl":"https://github.com/elastic/elasticsearch/blob/db6a809a667c081ca1dc7500389d26975573215f/libs/simdvec/src/main/java/org/elasticsearch/simdvec/ESVectorUtil.java#L344-L380","documentation":"Thrown by ipByteBinByte(byte[] q, byte[] d): inner product of a byte query against a 'bin'-packed byte document used by ES93 binary quantization scoring. Each document byte encodes B_QUERY (=4) query bytes, so the contract is q.length == d.length * B_QUERY (B_QUERY is 4, defined in ESVectorUtilSupport). The message embeds the actual q.length, B_QUERY and d.length so you can see which side is wrong.","triggerScenarios":"Calling ipByteBinByte where the query byte length is not exactly 4 times the document byte length. Typical when the query vector was not 4-bit quantized to match the bin-packed document, or when the document was not bin-packed (e.g. a raw int8 vector was supplied instead of a binary-quantized one).","commonSituations":"ES93 binary quantization scorer wired to a non-binary document vector; query encoder changed (e.g. from ES93 to a plain int8 encoder) without re-routing the scorer; dimension configuration that doesn't satisfy discretize(dims,64) producing the expected packed length; stale segment from before a reindex.","solutions":["Verify the ES93 contract: the document must be bin-packed (1 bit per dim) and the query must be the 4-byte-per-64-dims quantized form, so q.length == d.length * 4.","Log q.length, d.length and d.length * 4 at the call site to localize which side drifted.","Ensure the same ES93 quantizer is used at index and query time; do not mix ES93 bin documents with plain int8 query encoding.","If you cannot guarantee the 4x relation, route to a different scorer (e.g. ipByteBit or dotProduct) that matches your actual encodings."],"exampleFix":"// before\nlong ip = ESVectorUtil.ipByteBinByte(qBytes, docBytes); // q.length != d.length * 4\n\n// after\nfinal int B_QUERY = 4;\nif (qBytes.length != docBytes.length * B_QUERY) {\n    throw new IllegalArgumentException(\"ipByteBinByte contract violated: q.length=\"\n        + qBytes.length + \" expected d.length*\" + B_QUERY + \"=\" + (docBytes.length * B_QUERY));\n}\nlong ip = ESVectorUtil.ipByteBinByte(qBytes, docBytes);","handlingStrategy":"validation","validationCode":"final int B_QUERY = 4; // org.elasticsearch.simdvec.internal.vectorization.ESVectorUtilSupport.B_QUERY\nif (q.length != d.length * B_QUERY) {\n    throw new IllegalArgumentException(\"ipByteBinByte contract: q.length=\" + q.length\n        + \" must equal d.length*B_QUERY=\" + (d.length * B_QUERY));\n}\nlong ip = ESVectorUtil.ipByteBinByte(q, d);","typeGuard":null,"tryCatchPattern":"try {\n    long ip = ESVectorUtil.ipByteBinByte(q, d);\n} catch (IllegalArgumentException e) {\n    throw new QueryException(\"ipByteBinByte: query not 4-byte-per-pack relative to bin document\", e);\n}","preventionTips":["Use the ES93 quantizer consistently for both index and query so q.length == d.length * 4 holds.","Do not route plain int8 documents or queries into the ES93 bin scorer; pick ipByteBit / dotProduct instead.","Log q.length, d.length and d.length*4 at the call site to localize drift after reindex or encoder swaps."],"tags":["vector","simd","dimensions","binary-quantization","es93","elasticsearch","knn"],"analyzedSha":"db6a809a667c081ca1dc7500389d26975573215f","analyzedAt":"2026-08-12T01:39:14.192Z","schemaVersion":2},"datasetVersion":"2026-08-12T06:17:24.410Z"}