{"record":{"id":"044c0fcfd6485735","repo":"prestodb/presto","slug":"field-s-has-unexpected-position-count-expected","errorCode":null,"errorMessage":"field %s has unexpected position count. Expected: %s, actual: %s","messagePattern":"field (.+?) has unexpected position count\\. Expected: (.+?), actual: (.+?)","errorType":"exception","errorClass":"IllegalStateException","httpStatus":null,"severity":"error","filePath":"presto-common/src/main/java/com/facebook/presto/common/block/RowBlockBuilder.java","lineNumber":238,"sourceCode":"        if (rowIsNull.length <= positionCount) {\n            int newSize = BlockUtil.calculateNewArraySize(rowIsNull.length);\n            rowIsNull = Arrays.copyOf(rowIsNull, newSize);\n            fieldBlockOffsets = Arrays.copyOf(fieldBlockOffsets, newSize + 1);\n        }\n\n        if (isNull) {\n            fieldBlockOffsets[positionCount + 1] = fieldBlockOffsets[positionCount];\n        }\n        else {\n            fieldBlockOffsets[positionCount + 1] = fieldBlockOffsets[positionCount] + 1;\n        }\n        rowIsNull[positionCount] = isNull;\n        hasNullRow |= isNull;\n        positionCount++;\n\n        for (int i = 0; i < numFields; i++) {\n            if (fieldBlockBuilders[i].getPositionCount() != fieldBlockOffsets[positionCount]) {\n                throw new IllegalStateException(format(\"field %s has unexpected position count. Expected: %s, actual: %s\", i, fieldBlockOffsets[positionCount], fieldBlockBuilders[i].getPositionCount()));\n            }\n        }\n\n        if (blockBuilderStatus != null) {\n            blockBuilderStatus.addBytes(Integer.BYTES + Byte.BYTES);\n        }\n    }\n\n    @Override\n    public Block build()\n    {\n        if (currentEntryOpened) {\n            throw new IllegalStateException(\"Current entry must be closed before the block can be built\");\n        }\n        Block[] fieldBlocks = new Block[numFields];\n        for (int i = 0; i < numFields; i++) {\n            fieldBlocks[i] = fieldBlockBuilders[i].build();\n        }","sourceCodeStart":220,"sourceCodeEnd":256,"githubUrl":"https://github.com/prestodb/presto/blob/55bb57d202de3b926896fa966c2c4a44c779634e/presto-common/src/main/java/com/facebook/presto/common/block/RowBlockBuilder.java#L220-L256","documentation":"RowBlockBuilder tracks each field's element count in fieldBlockOffsets. When a row entry is added, the offset recorded for the new position must equal the actual position count of each field's block builder. If they diverge, the builder's internal offsets are inconsistent with the underlying field blocks, so the library throws to prevent producing a corrupt row block.","triggerScenarios":"Writing a different number of positions to a field builder than the row expects — e.g. calling fieldBlockBuilder.appendNull() or writing multiple values into one field within a single row entry, or calling appendStructure with a block that populates fields unevenly, then closeEntry().","commonSituations":"Hand-written row type serialization/deserialization where each column must contribute exactly one value per row; code that mistakenly writes two values (like writing a slice plus its length) into a single field entry; copying logic that skips a field on some branch.","solutions":["Verify every fieldBlockBuilders[i] receives exactly one value (or one appendNull) per row entry","Fix loops that write more than one element per field per row","On deserialization, ensure block.getPositionCount() matches the expected field offsets before closeEntry","Never appendNull on an individual field builder inside an opened entry if the row itself already tracks nulls"],"exampleFix":"// before\nBlockBuilder entry = rowBuilder.beginBlockEntry();\nentry.appendNull();\nentry.appendNull(); // two positions in one field -> offsets mismatch\nrowBuilder.closeEntry();\n// after\nBlockBuilder entry = rowBuilder.beginBlockEntry();\nentry.appendNull(); // exactly one value per field per row\nrowBuilder.closeEntry();","handlingStrategy":"validation","validationCode":"// per row entry, ensure every field got exactly one value\n// after writing the row but before closeEntry():\nfor (int i = 0; i < fieldBlockBuilders.length; i++) {\n    // each field must advance exactly once per row\n    checkState(fieldBlockBuilders[i].getPositionCount() == expectedPositions,\n        \"field %s advanced %s times, expected %s\", i, fieldBlockBuilders[i].getPositionCount(), expectedPositions);\n}\n","typeGuard":null,"tryCatchPattern":"try {\n    rowBuilder.closeEntry();\n} catch (IllegalStateException e) {\n    if (e.getMessage().contains(\"unexpected position count\")) {\n        throw new IllegalStateException(\"wrote wrong number of values into a row field; check field write loop\", e);\n    }\n    throw e;\n}","preventionTips":["Write exactly one value or one appendNull per field per row entry","Never call appendNull twice on one field builder inside a single entry","Count field writes in loops copying multi-field rows","Unit-test row writers with nested and null fields"],"tags":["presto","row-block","corrupt-state","block-builder"],"backgroundTag":"block-field-offset-mismatch","analyzedSha":"55bb57d202de3b926896fa966c2c4a44c779634e","analyzedAt":"2026-09-04T12:50:26.162Z","contentChangedAt":"2026-09-04T12:50:26.162Z","schemaVersion":2},"datasetVersion":"2026-09-11T21:17:09.523Z"}