{"record":{"id":"63f086cb54fdf3cd","repo":"languagetool-org/languagetool","slug":"invalid-word-cannot-be-empty-or-whitespace-only","errorCode":null,"errorMessage":"Invalid word, cannot be empty or whitespace only","messagePattern":"Invalid word, cannot be empty or whitespace only","errorType":"validation","errorClass":"BadRequestException","httpStatus":400,"severity":"error","filePath":"languagetool-server/src/main/java/org/languagetool/server/DatabaseAccessOpenSource.java","lineNumber":323,"sourceCode":"    } catch (ExecutionException e) {\n      logger.warn(\"Failure in getOrCreateClientId with client '\" + client + \"': \", e);\n      return null;\n    }\n  }\n\n  @Override\n  List<DictGroupEntry> getDictGroups(Long userId) {\n    return Collections.emptyList();\n  }\n\n  @Override\n  Long getOrCreateDictGroup(Long userId, String groupName) {\n    throw new NotImplementedException(NON_PREMIUM_MSG);\n  }\n\n  private void validateWord(String word) {\n    if (word == null || word.trim().isEmpty()) {\n      throw new BadRequestException(\"Invalid word, cannot be empty or whitespace only\");\n    }\n    if (WHITESPACE_PATTERN.matcher(word).matches()) {\n      throw new BadRequestException(\"Invalid word, you can only add words that don't contain spaces: '\" + word + \"'\");\n    }\n  }\n\n  /** For unit tests only! */\n  @Override\n  public void createAndFillTestTables(boolean mysql, List<String> skipStatements) {\n    try (SqlSession session = sqlSessionFactory.openSession(true)) {\n      System.out.println(\"Setting up tables and adding test user...\");\n      String[] statements = { \"org.languagetool.server.UserDictMapper.createUserTable\",\n        \"org.languagetool.server.UserDictMapper.createIgnoreWordTable\" };\n      for (String statement : statements) {\n        if (skipStatements.contains(statement)) {\n          continue;\n        }\n        if (mysql) {","sourceCodeStart":305,"sourceCodeEnd":341,"githubUrl":"https://github.com/languagetool-org/languagetool/blob/2e990059ce67d5e2a0f7f7ca5d31160c6709df4b/languagetool-server/src/main/java/org/languagetool/server/DatabaseAccessOpenSource.java#L305-L341","documentation":"validateWord rejects empty or whitespace-only words before they are stored in a user dictionary, throwing BadRequestException. A user-vocabulary entry must contain at least one non-whitespace character; the server refuses the request as a client input error.","triggerScenarios":"Calling addWord (or the /vocabulary REST endpoint) with a word that is null, \"\", or consists only of whitespace (e.g. \" \", \"\\t\").","commonSituations":"Client sends an empty word param from a form/UI; word extracted by a buggy regex that yields empty string; trimming done after validation; JSON body field missing and defaulted to empty.","solutions":["Trim and check the word for emptiness on the client before calling addWord.","Filter out empty/whitespace-only tokens before batch-adding words.","Fix the upstream extraction logic producing empty tokens.","Ensure the API parameter is actually provided in the request (not dropped/null)."],"exampleFix":"// before\nserver.addWord(userId, word);\n// after\nString trimmed = word == null ? \"\" : word.trim();\nif (!trimmed.isEmpty()) {\n  server.addWord(userId, trimmed);\n}","handlingStrategy":"validation","validationCode":"function isValidWord(w) {\n  return typeof w === 'string' && w.trim().length > 0;\n}\nif (!isValidWord(word)) throw new Error('word must be non-empty');","typeGuard":"boolean isNonEmptyString(Object o) {\n  return o instanceof String && !((String) o).trim().isEmpty();\n}","tryCatchPattern":"try {\n  api.addWord(userId, word);\n} catch (BadRequestException e) {\n  if (e.getMessage().contains(\"cannot be empty\")) {\n    log.warn(\"Skipping empty word for user \" + userId);\n  } else throw e;\n}","preventionTips":["Trim input before sending to the API","Skip empty tokens in batch add operations","Validate form fields as required+non-blank in the UI"],"tags":["validation","bad-request","dictionary"],"backgroundTag":"empty-required-field","analyzedSha":"2e990059ce67d5e2a0f7f7ca5d31160c6709df4b","analyzedAt":"2026-09-06T09:20:17.015Z","contentChangedAt":"2026-09-06T09:20:17.015Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}