{"record":{"id":"bdc0348bba8a4849","repo":"prestodb/presto","slug":"dictionarysourceids-must-be-the-same","errorCode":null,"errorMessage":"dictionarySourceIds must be the same","messagePattern":"dictionarySourceIds must be the same","errorType":"exception","errorClass":"java.lang.IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"presto-common/src/main/java/com/facebook/presto/common/Page.java","lineNumber":291,"sourceCode":"            if (remapIndex[position] == -1) {\n                dictionaryPositionsToCopy[numberOfIndexes] = position;\n                remapIndex[position] = numberOfIndexes;\n                numberOfIndexes++;\n            }\n        }\n\n        // entire dictionary is referenced\n        if (numberOfIndexes == dictionarySize) {\n            return blocks;\n        }\n\n        // compact the dictionaries\n        int[] newIds = getNewIds(positionCount, firstDictionaryBlock, remapIndex);\n        List<DictionaryBlock> outputDictionaryBlocks = new ArrayList<>(blocks.size());\n        DictionaryId newDictionaryId = randomDictionaryId();\n        for (DictionaryBlock dictionaryBlock : blocks) {\n            if (!firstDictionaryBlock.getDictionarySourceId().equals(dictionaryBlock.getDictionarySourceId())) {\n                throw new IllegalArgumentException(\"dictionarySourceIds must be the same\");\n            }\n\n            try {\n                Block compactDictionary = dictionaryBlock.getDictionary().copyPositions(dictionaryPositionsToCopy, 0, numberOfIndexes);\n                outputDictionaryBlocks.add(new DictionaryBlock(positionCount, compactDictionary, newIds, true, newDictionaryId));\n            }\n            catch (UnsupportedOperationException e) {\n                // ignore if copy positions is not supported for the dictionary\n                outputDictionaryBlocks.add(dictionaryBlock);\n            }\n        }\n        return outputDictionaryBlocks;\n    }\n\n    private static int[] getNewIds(int positionCount, DictionaryBlock dictionaryBlock, int[] remapIndex)\n    {\n        int[] newIds = new int[positionCount];\n        for (int i = 0; i < positionCount; i++) {","sourceCodeStart":273,"sourceCodeEnd":309,"githubUrl":"https://github.com/prestodb/presto/blob/55bb57d202de3b926896fa966c2c4a44c779634e/presto-common/src/main/java/com/facebook/presto/common/Page.java#L273-L309","documentation":"During Page compaction of dictionary-encoded blocks, all DictionaryBlocks being compacted must share the same underlying dictionary (verified via DictionarySourceId). compactRelatedBlocks builds one compacted dictionary from the first block, so if any other block was built from a different dictionary, the compaction would silently corrupt data; the library refuses by throwing this IllegalArgumentException.","triggerScenarios":"Calling Page.compactBlocks/compactRelatedBlocks on a Page whose Block array contains multiple DictionaryBlocks created from different dictionaries (different DictionaryId), e.g. after mixing dictionary-encoded segments from different sources into one Page.","commonSituations":"Operators/scan pipelines that concatenate pages from different splits where each split dictionary-encoded its column independently; column readers that re-dictionary-encode without merging dictionary ids.","solutions":["Ensure all DictionaryBlocks in the Page share one dictionary, or convert some blocks to non-dictionary blocks before compaction","Unwrap/decode DictionaryBlocks (e.g. via block.getLoadedBlock() or copying to lazy/plain blocks) before calling compactBlocks","Check DictionaryBlock.getDictionarySourceId() equality yourself before compacting and rebuild the Page consistently","Upgrade/regenerate the dictionary so blocks produced in the same compaction batch originate from one dictionary source"],"exampleFix":"// before\nDictionaryBlock a = new DictionaryBlock(dictionaryA, idsA);\nDictionaryBlock b = new DictionaryBlock(dictionaryB, idsB);\npage.compactBlocks(); // throws\n// after\nBlock aPlain = a.copyPositions(a.getRange(0, a.getPositionCount()), 0, a.getPositionCount()); // or decode\nPage fixed = new Page(aPlain, b.copyPositions(...));\nfixed.compactBlocks();","handlingStrategy":"validation","validationCode":"DictionaryId first = ((DictionaryBlock) blocks.get(0)).getDictionarySourceId();\nfor (Block b : blocks) {\n    if (b instanceof DictionaryBlock && !first.equals(((DictionaryBlock) b).getDictionarySourceId())) {\n        throw new IllegalArgumentException(\"mixed dictionaries; decode blocks before compaction\");\n    }\n}","typeGuard":"boolean sameDictionary(Block a, Block b) {\n    return !(a instanceof DictionaryBlock) || !(b instanceof DictionaryBlock)\n        || a.getDictionarySourceId().equals(b.getDictionarySourceId());\n}","tryCatchPattern":"try {\n    page = page.compactBlocks();\n} catch (IllegalArgumentException e) {\n    if (!e.getMessage().contains(\"dictionarySourceIds\")) throw e;\n    page = decodeToPlainBlocks(page); // fallback: materialize dictionaries\n}","preventionTips":["Decode dictionary blocks when merging pages from different splits","Log/verify DictionarySourceId equality in custom Block implementations","Avoid re-using randomDictionaryId outputs across page boundaries"],"tags":["presto","dictionary-encoding","block-compaction","illegal-argument"],"backgroundTag":"dictionary-source-id-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"}