{"record":{"id":"134c11926039b018","repo":"elastic/elasticsearch","slug":"geoip-max-cache-size-must-be-0-or-greater","errorCode":null,"errorMessage":"geoip max cache size must be 0 or greater","messagePattern":"geoip max cache size must be 0 or greater","errorType":"validation","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"modules/ip-location/src/main/java/org/elasticsearch/ingest/geoip/GeoIpCache.java","lineNumber":53,"sourceCode":"     * something not being in the cache because the data doesn't exist in the database.\n     */\n    // visible for testing\n    static final Object NO_RESULT = new Object() {\n        @Override\n        public String toString() {\n            return \"NO_RESULT\";\n        }\n    };\n\n    private final Cache<CacheKey, Object> cache;\n    private final LongSupplier relativeNanoTimeProvider;\n    private final LongAdder hitsTimeInNanos = new LongAdder();\n    private final LongAdder missesTimeInNanos = new LongAdder();\n\n    // package private for testing\n    GeoIpCache(long maxSize, LongSupplier relativeNanoTimeProvider) {\n        if (maxSize < 0) {\n            throw new IllegalArgumentException(\"geoip max cache size must be 0 or greater\");\n        }\n        this.relativeNanoTimeProvider = relativeNanoTimeProvider;\n        this.cache = CacheBuilder.<CacheKey, Object>builder().setMaximumWeight(maxSize).build();\n    }\n\n    GeoIpCache(long maxSize) {\n        this(maxSize, System::nanoTime);\n    }\n\n    @SuppressWarnings(\"unchecked\")\n    <RESPONSE> RESPONSE putIfAbsent(ProjectId projectId, String ip, String databasePath, Function<String, RESPONSE> retrieveFunction) {\n        // can't use cache.computeIfAbsent due to the elevated permissions for the jackson (run via the cache loader)\n        CacheKey cacheKey = new CacheKey(projectId, ip, databasePath);\n        long cacheStart = relativeNanoTimeProvider.getAsLong();\n        // intentionally non-locking for simplicity...it's OK if we re-put the same key/value in the cache during a race condition.\n        Object response = cache.get(cacheKey);\n        long cacheRequestTime = relativeNanoTimeProvider.getAsLong() - cacheStart;\n","sourceCodeStart":35,"sourceCodeEnd":71,"githubUrl":"https://github.com/elastic/elasticsearch/blob/db6a809a667c081ca1dc7500389d26975573215f/modules/ip-location/src/main/java/org/elasticsearch/ingest/geoip/GeoIpCache.java#L35-L71","documentation":"Thrown by the GeoIpCache constructor when maxSize is negative. The cache backs the geoip lookup results per (project, ip, databasePath); zero is allowed (no caching), negatives are not. IllegalArgumentException surfaces during cache construction, typically from a bad setting parse.","triggerScenarios":"GeoIpCache(maxSize) or GeoIpCache(maxSize, nanoTimeProvider) called with maxSize < 0. Usually the maxSize originates from a geoip cache size setting that resolved to a negative number.","commonSituations":"A user setting cache.max_size to a negative value; an arithmetic/overflow that produces a negative; a default-value bug in a setting parser.","solutions":["Set the cache size setting to 0 or a positive integer.","Find the setting feeding maxSize and validate its parsed value before construction.","If this fires from internal code, ensure no subtraction can underflow into a negative."],"exampleFix":null,"handlingStrategy":"validation","validationCode":"long sanitizeCacheSize(long v) {\n    if (v < 0) throw new IllegalArgumentException(\"geoip max cache size must be 0 or greater\");\n    return v;\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Always set the cache size setting to 0 or a positive integer.","Validate any computed/derived size before constructing GeoIpCache.","Guard against integer underflow when deriving the size arithmetically."],"tags":["geoip","cache","configuration","validation"],"backgroundTag":null,"analyzedSha":"db6a809a667c081ca1dc7500389d26975573215f","analyzedAt":"2026-08-12T01:39:14.192Z","schemaVersion":2},"datasetVersion":"2026-08-12T13:17:24.610Z"}