{"record":{"id":"2ec4f90e4781c89c","repo":"languagetool-org/languagetool","slug":"use-of-cachettlseconds-without-also-setting-caches","errorCode":null,"errorMessage":"Use of cacheTTLSeconds without also setting cacheSize has no effect.","messagePattern":"Use of cacheTTLSeconds without also setting cacheSize has no effect\\.","errorType":"console","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"languagetool-server/src/main/java/org/languagetool/server/HTTPServerConfig.java","lineNumber":399,"sourceCode":"        if (rulesConfigFilePath != null) {\n          rulesConfigFile = new File(rulesConfigFilePath);\n          if (!rulesConfigFile.exists() || !rulesConfigFile.isFile()) {\n            throw new RuntimeException(\"Rules Configuration file cannot be found: \" + rulesConfigFile);\n          }\n        }\n        String remoteRulesConfigFilePath = getOptionalProperty(props, \"remoteRulesFile\", null);\n        if (remoteRulesConfigFilePath != null) {\n          remoteRulesConfigFile = new File(remoteRulesConfigFilePath);\n          if (!remoteRulesConfigFile.exists() || !remoteRulesConfigFile.isFile()) {\n            throw new RuntimeException(\"Remote rules configuration file cannot be found: \" + remoteRulesConfigFile);\n          }\n        }\n        cacheSize = Integer.parseInt(getOptionalProperty(props, \"cacheSize\", \"0\"));\n        if (cacheSize < 0) {\n          throw new IllegalArgumentException(\"Invalid value for cacheSize: \" + cacheSize + \", use 0 to deactivate cache\");\n        }\n        if (props.containsKey(\"cacheTTLSeconds\") && !props.containsKey(\"cacheSize\")) {\n          throw new IllegalArgumentException(\"Use of cacheTTLSeconds without also setting cacheSize has no effect.\");\n        }\n        cacheTTLSeconds = Integer.parseInt(getOptionalProperty(props, \"cacheTTLSeconds\", \"300\"));\n        maxErrorsPerWordRate = Float.parseFloat(getOptionalProperty(props, \"maxErrorsPerWordRate\", \"0\"));\n        suggestionsEnabled = Boolean.parseBoolean(getOptionalProperty(props, \"suggestionsEnabled\", \"true\"));\n        maxSpellingSuggestions = Integer.parseInt(getOptionalProperty(props, \"maxSpellingSuggestions\", \"0\"));\n        blockedReferrers = Arrays.asList(getOptionalProperty(props, \"blockedReferrers\", \"\").split(\",\\\\s*\"));\n        setTrustedSources(getOptionalProperty(props, \"trustedSources\", null));\n        String premiumAlwaysValue = props.getProperty(\"premiumAlways\");\n        if (premiumAlwaysValue != null) {\n          premiumAlways = Boolean.parseBoolean(premiumAlwaysValue.trim());\n          if (premiumAlways) {\n            System.out.println(\"*** Running in PREMIUM-ALWAYS mode\");\n          }\n        }\n        premiumOnly = Boolean.valueOf(getOptionalProperty(props, \"premiumOnly\", \"false\").trim());\n        if (premiumOnly) {\n          if (!Premium.isPremiumVersion()) {\n            throw new IllegalArgumentException(\"Cannot use premiumOnly=true with non-premium version\");","sourceCodeStart":381,"sourceCodeEnd":417,"githubUrl":"https://github.com/languagetool-org/languagetool/blob/2e990059ce67d5e2a0f7f7ca5d31160c6709df4b/languagetool-server/src/main/java/org/languagetool/server/HTTPServerConfig.java#L381-L417","documentation":"Setting 'cacheTTLSeconds' only has an effect when the result cache is enabled via 'cacheSize'. To avoid a silently ineffective configuration, the server throws this IllegalArgumentException when cacheTTLSeconds is present but cacheSize is not set.","triggerScenarios":"Server properties file contains 'cacheTTLSeconds=...' while 'cacheSize' is absent. Even with the default cacheSize of 0 (cache off), a TTL alone does nothing, so the config is rejected.","commonSituations":"Operator tunes cache expiry but forgets to enable/set cacheSize; docs examples showing only the TTL option; config files merged from different sources where cacheSize was dropped.","solutions":["Add a 'cacheSize' property (e.g. cacheSize=1000) alongside cacheTTLSeconds to enable the cache","Remove the 'cacheTTLSeconds' property if caching is not intended","Both keys must appear together for a working cached setup"],"exampleFix":"// before (server.properties)\ncacheTTLSeconds=300\n\n// after (server.properties)\ncacheSize=1000\ncacheTTLSeconds=300","handlingStrategy":"validation","validationCode":"if (props.containsKey(\"cacheTTLSeconds\") && !props.containsKey(\"cacheSize\")) {\n    throw new IllegalStateException(\"cacheTTLSeconds requires cacheSize to be set\");\n}","typeGuard":null,"tryCatchPattern":"try {\n    serverConfig = new HTTPServerConfig(props);\n} catch (IllegalArgumentException e) {\n    if (e.getMessage().contains(\"cacheTTLSeconds without also setting cacheSize\")) {\n        props.setProperty(\"cacheSize\", \"1000\");\n        serverConfig = new HTTPServerConfig(props);\n    } else { throw e; }\n}","preventionTips":["Always set cacheSize and cacheTTLSeconds as a pair","Document this coupling in your configuration template comments","Lint config files for cache-related keys as a unit"],"tags":["java","languagetool","invalid-config-value","cache","server-config"],"backgroundTag":"conflicting-config-options","analyzedSha":"2e990059ce67d5e2a0f7f7ca5d31160c6709df4b","analyzedAt":"2026-09-06T09:20:17.015Z","contentChangedAt":"2026-09-06T09:20:17.015Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}