{"record":{"id":"b000570ccb4e1f06","repo":"languagetool-org/languagetool","slug":"use-parameter-dicts-not-dict-in-get-words-ap","errorCode":null,"errorMessage":"Use parameter 'dicts', not 'dict' in GET /words API method.","messagePattern":"Use parameter 'dicts', not 'dict' in GET /words API method\\.","errorType":"http","errorClass":"IllegalArgumentException","httpStatus":400,"severity":"error","filePath":"languagetool-server/src/main/java/org/languagetool/server/ApiV2.java","lineNumber":196,"sourceCode":"  }\n\n  private void handleIpLogMatch(HttpExchange httpExchange, String remoteAddress, Map<String, String> parameters) {\n    Logger logger = LoggerFactory.getLogger(ApiV2.class);\n    InetSocketAddress localAddress = httpExchange.getLocalAddress();\n    logger.info(String.format(\"Found log-my-IP text in request from: %s to: %s, requestParams: %s\", remoteAddress, localAddress.toString(), parameters));\n  }\n\n  private void handleWordsRequest(HttpExchange httpExchange, Map<String, String> params, HTTPServerConfig config) throws Exception {\n    ensureGetMethod(httpExchange, \"/words\");\n    UserLimits limits = getUserLimits(params, config);\n    DatabaseAccess db = DatabaseAccess.getInstance();\n    int offset = params.get(\"offset\") != null ? Integer.parseInt(params.get(\"offset\")) : 0;\n    int limit = params.get(\"limit\") != null ? Integer.parseInt(params.get(\"limit\")) : 10;\n    logger.info(\"Started reading dictionary for user: {}, offset: {}, limit: {}, dict_cache: {}, dict: {}\",\n      limits.getPremiumUid(), offset, limit, limits.getDictCacheSize(), params.get(\"dict\"));\n\n    if (params.containsKey(\"dict\")) {\n      throw new IllegalArgumentException(\"Use parameter 'dicts', not 'dict' in GET /words API method.\");\n    }\n\n    // optional parameter: groups in comma separated list\n    List<String> groups = null;\n    if (params.containsKey(\"dicts\")) {\n      groups = Arrays.asList(params.get(\"dicts\").split(\",\"));\n    } else if (limits.getAccount() != null &&\n               limits.getAccount().getDefaultDictionary() != null &&\n               !limits.getAccount().getDefaultDictionary().isEmpty()) {\n      groups = Collections.singletonList(limits.getAccount().getDefaultDictionary());\n    }\n    long start = System.nanoTime();\n    List<String> words = db.getWords(limits, groups, offset, limit);\n    //List<String> words = db.getWords(limits.getPremiumUid(), groups, offset, limit);\n    long durationMilliseconds = TimeUnit.NANOSECONDS.toMillis(System.nanoTime() - start);\n    logger.info(\"Finished reading dictionary for user: {}, offset: {}, limit: {}, dict_cache: {}, dict: {}, size: {} in {}ms\",\n      limits.getPremiumUid(), offset, limit, limits.getDictCacheSize(), params.get(\"dict\"), words.size(), durationMilliseconds);\n    writeListResponse(\"words\", words, httpExchange);","sourceCodeStart":178,"sourceCodeEnd":214,"githubUrl":"https://github.com/languagetool-org/languagetool/blob/2e990059ce67d5e2a0f7f7ca5d31160c6709df4b/languagetool-server/src/main/java/org/languagetool/server/ApiV2.java#L178-L214","documentation":"The GET /v2/words endpoint was changed to accept only the plural parameter 'dicts' (a comma-separated list of dictionary names); the old singular 'dict' parameter is explicitly rejected with an IllegalArgumentException to force callers to migrate. The exception is thrown before any dictionary lookup happens.","triggerScenarios":"Calling GET /v2/words with '?dict=my_dict' instead of '?dicts=my_dict'; legacy client code written against the pre-rename API still passing 'dict'.","commonSituations":"Old integrations or bookmarks written before the API rename; copied example snippets from outdated blog posts or documentation; wrappers that still serialize a 'dict' query parameter.","solutions":["Rename the query parameter from 'dict' to 'dicts' in the request URL.","If you need multiple dictionaries, pass them as a comma-separated list: dicts=name1,name2.","Update any client SDK or wrapper that still emits the deprecated 'dict' parameter."],"exampleFix":"// before\nGET /v2/words?dict=my_personal_dict&username=u&token=t\n// after\nGET /v2/words?dicts=my_personal_dict&username=u&token=t","handlingStrategy":"validation","validationCode":"const url = new URL('/v2/words', base);\nif (url.searchParams.has('dict')) throw new Error('Use \"dicts\", not \"dict\", for GET /v2/words');","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Use the plural 'dicts' query parameter with a comma-separated list.","Search client code for 'dict=' and migrate occurrences to 'dicts=' after an upgrade.","Pin and review server version notes when the /words API changes."],"tags":["http","rest-api","deprecated","languagetool"],"backgroundTag":"deprecated-api-usage","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"}