{"record":{"id":"29a16cfea31ab735","repo":"microg/GmsCore","slug":"must-set-attenuationbucketthresholddb","errorCode":null,"errorMessage":"Must set attenuationBucketThresholdDb","messagePattern":"Must set attenuationBucketThresholdDb","errorType":"validation","errorClass":"IllegalStateException","httpStatus":null,"severity":"error","filePath":"play-services-nearby/src/main/java/com/google/android/gms/nearby/exposurenotification/DailySummariesConfig.java","lineNumber":188,"sourceCode":"    /**\n     * A builder for {@link DailySummariesConfig}.\n     */\n    public static class DailySummariesConfigBuilder {\n        private Double[] reportTypeWeights = new Double[ReportType.VALUES];\n        private Double[] infectiousnessWeights = new Double[Infectiousness.VALUES];\n        private List<Integer> attenuationBucketThresholdDb;\n        private List<Double> attenuationBucketWeights;\n        private int daysSinceExposureThreshold;\n        private double minimumWindowScore;\n\n        public DailySummariesConfigBuilder() {\n            Arrays.fill(reportTypeWeights, 0.0);\n            Arrays.fill(infectiousnessWeights, 0.0);\n        }\n\n        public DailySummariesConfig build() {\n            if (attenuationBucketThresholdDb == null)\n                throw new IllegalStateException(\"Must set attenuationBucketThresholdDb\");\n            if (attenuationBucketWeights == null)\n                throw new IllegalStateException(\"Must set attenuationBucketWeights\");\n            DailySummariesConfig config = new DailySummariesConfig();\n            config.reportTypeWeights = Arrays.asList(reportTypeWeights);\n            config.infectiousnessWeights = Arrays.asList(infectiousnessWeights);\n            config.attenuationBucketThresholdDb = attenuationBucketThresholdDb;\n            config.attenuationBucketWeights = attenuationBucketWeights;\n            config.daysSinceExposureThreshold = daysSinceExposureThreshold;\n            config.minimumWindowScore = minimumWindowScore;\n            return config;\n        }\n\n        /**\n         * See {@link #getAttenuationBucketThresholdDb()} and {@link #getAttenuationBucketWeights()}\n         */\n        public DailySummariesConfigBuilder setAttenuationBuckets(List<Integer> thresholds, List<Double> weights) {\n            attenuationBucketThresholdDb = new ArrayList<>(thresholds);\n            attenuationBucketWeights = new ArrayList<>(weights);","sourceCodeStart":170,"sourceCodeEnd":206,"githubUrl":"https://github.com/microg/GmsCore/blob/157c9d86ac46c195a86c2f15ab55c84036223f95/play-services-nearby/src/main/java/com/google/android/gms/nearby/exposurenotification/DailySummariesConfig.java#L170-L206","documentation":"DailySummariesConfig.Builder.build() requires attenuationBucketThresholdDb to be explicitly set before constructing the config. The library throws IllegalStateException because the Exposure Notification API cannot compute per-exposure summary weights without the attenuation bucket boundaries. This is a fail-fast builder validation to prevent passing an incomplete config to the API.","triggerScenarios":"Calling DailySummariesConfig.Builder.build() without first calling setAttenuationBucketThresholdDb(List<Integer>) on the builder.","commonSituations":"Developers assemble a DailySummariesConfig but omit the threshold list because other builder fields (reportTypeWeights, infectiousnessWeights) have defaults filled with zeros, making it easy to assume thresholds are optional too.","solutions":["Call builder.setAttenuationBucketThresholdDb(...) with exactly 3 threshold values (in dB, e.g. [30, 40, 60]) before build()","Check every required builder setter is invoked; set weights after thresholds so both validations pass","If building conditionally, ensure the threshold branch is always executed"],"exampleFix":"// before\nDailySummariesConfig config = new DailySummariesConfig.Builder()\n    .setReportTypeWeights(...)\n    .build();\n// after\nDailySummariesConfig config = new DailySummariesConfig.Builder()\n    .setAttenuationBucketThresholdDb(Arrays.asList(30, 40, 60))\n    .setAttenuationBucketWeights(...)\n    .setReportTypeWeights(...)\n    .build();","handlingStrategy":"validation","validationCode":"List<Integer> thresholds = Arrays.asList(30, 40, 60);\nif (builder == null || thresholds == null || thresholds.size() != 3) {\n    throw new IllegalStateException(\"attenuationBucketThresholdDb must be set (3 values)\");\n}\nDailySummariesConfig config = builder\n    .setAttenuationBucketThresholdDb(thresholds)\n    .build();","typeGuard":null,"tryCatchPattern":"try {\n    DailySummariesConfig config = builder.build();\n} catch (IllegalStateException e) {\n    Log.w(TAG, \"Incomplete DailySummariesConfig: \" + e.getMessage());\n}","preventionTips":["Always call setAttenuationBucketThresholdDb with exactly 3 dB values before build()","Centralize config construction in one helper so required setters cannot be skipped","Write a unit test constructing a fully populated builder"],"tags":["java","builder-validation","exposure-notification"],"backgroundTag":"missing-required-argument","analyzedSha":"157c9d86ac46c195a86c2f15ab55c84036223f95","analyzedAt":"2026-09-06T17:27:33.892Z","contentChangedAt":"2026-09-06T17:27:33.892Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}