{"record":{"id":"3d4afd9f74ed8baf","repo":"prestodb/presto","slug":"impossible-boolean-statistics","errorCode":null,"errorMessage":"Impossible boolean statistics","messagePattern":"Impossible boolean statistics","errorType":"exception","errorClass":"VerifyException","httpStatus":null,"severity":"warning","filePath":"presto-parquet/src/main/java/com/facebook/presto/parquet/predicate/TupleDomainParquetPredicate.java","lineNumber":159,"sourceCode":"            boolean hasNullValue)\n    {\n        checkArgument(minimums.size() == maximums.size(), \"Expected minimums and maximums to have the same size\");\n\n        List<Range> ranges = new ArrayList<>();\n        if (type.equals(BOOLEAN)) {\n            boolean hasTrueValues = minimums.stream().anyMatch(value -> (boolean) value) || maximums.stream().anyMatch(value -> (boolean) value);\n            boolean hasFalseValues = minimums.stream().anyMatch(value -> !(boolean) value) || maximums.stream().anyMatch(value -> !(boolean) value);\n            if (hasTrueValues && hasFalseValues) {\n                return Domain.all(type);\n            }\n            if (hasTrueValues) {\n                return Domain.create(ValueSet.of(type, true), hasNullValue);\n            }\n            if (hasFalseValues) {\n                return Domain.create(ValueSet.of(type, false), hasNullValue);\n            }\n            // All nulls case is handled earlier\n            throw new VerifyException(\"Impossible boolean statistics\");\n        }\n\n        if ((type.equals(BIGINT) || type.equals(TINYINT) || type.equals(SMALLINT) || type.equals(INTEGER))) {\n            for (int i = 0; i < minimums.size(); i++) {\n                long min = asLong(minimums.get(i));\n                long max = asLong(maximums.get(i));\n                if (isStatisticsOverflow(type, min, max)) {\n                    return Domain.create(ValueSet.all(type), hasNullValue);\n                }\n\n                ranges.add(Range.range(type, min, true, max, true));\n            }\n            checkArgument(!ranges.isEmpty(), \"cannot use empty ranges\");\n            return Domain.create(ValueSet.ofRanges(ranges), hasNullValue);\n        }\n\n        if (type.equals(REAL)) {\n            for (int i = 0; i < minimums.size(); i++) {","sourceCodeStart":141,"sourceCodeEnd":177,"githubUrl":"https://github.com/prestodb/presto/blob/55bb57d202de3b926896fa966c2c4a44c779634e/presto-parquet/src/main/java/com/facebook/presto/parquet/predicate/TupleDomainParquetPredicate.java#L141-L177","documentation":"When building a predicate Domain from Parquet boolean column statistics, getDomain assumes at least one of hasTrueValues/hasFalseValues is set once nulls-only cases were handled earlier. Reaching the final fall-through means statistics were internally inconsistent (neither true nor false values recorded despite non-null statistics), which should be impossible, so VerifyException is thrown to surface corrupted/contradictory stats.","triggerScenarios":"getDomain on a BOOLEAN-typed column index/statistics where hasNulls was handled but both hasTrueValues and hasFalseValues are false — i.e. statistics claim non-null presence without any true/false values, typically from malformed column index data.","commonSituations":"Corrupted or nonconformant Parquet column indexes written by buggy writers; stats-only (no rows) row groups with contradictory metadata; reading files written by tools that emit empty boolean statistics objects.","solutions":["Upgrade the reading library and/or regenerate the file so statistics conform to the spec","Disable predicate pushdown on boolean columns (or column indexes) to bypass statistics-based domain construction","Rewrite the file with a standard writer (parquet-mr/Spark) so stats are populated correctly","Validate the file's column indexes with parquet-tools"],"exampleFix":"// before\nthrow new VerifyException(\"Impossible boolean statistics\");\n// after\ndefault:\n    return Domain.create(ValueSet.all(type), hasNullValue); // tolerate broken stats","handlingStrategy":"fallback","validationCode":null,"typeGuard":null,"tryCatchPattern":"try {\n    domain = buildDomainFromStats(stats, type);\n} catch (VerifyException e) {\n    if (e.getMessage().equals(\"Impossible boolean statistics\")) {\n        domain = Domain.create(ValueSet.all(type), true); // no pushdown, safe fallback\n    } else throw e;\n}","preventionTips":["Regenerate files with conformant writers that populate boolean min/max stats correctly","Disable column-index pushdown for sources known to emit broken stats","Treat statistics as hints only — never assume internal consistency"],"tags":["parquet","statistics","predicate-pushdown","corrupt-file"],"backgroundTag":"inconsistent-column-statistics","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"}