languagetool-org/languagetool · error · IllegalArgumentException

username must be set

Error message

username must be set

What it means

DatabaseAccessOpenSource.getUserId(username, apiKey) validates its arguments before touching the database and throws IllegalArgumentException when the username is null, empty, or whitespace-only. The username is required to look up the user ID for API-key authentication.

Source

Thrown at languagetool-server/src/main/java/org/languagetool/server/DatabaseAccessOpenSource.java:206

      map.put("userId", userId);
      List<String> existingWords = session.selectList("org.languagetool.server.UserDictMapper.selectWord", map);
      if (existingWords.size() >= 1) {
        logger.info("Did not add '" + word + "' for user " + userId + " to list of ignored words, already exists");
        return false;
      } else {
        Date now = new Date();
        map.put("created_at", now);
        map.put("updated_at", now);
        int affectedRows = session.insert("org.languagetool.server.UserDictMapper.addWord", map);
        logger.info("Added '" + word + "' for user " + userId + " to list of ignored words, affectedRows: " + affectedRows);
        return affectedRows == 1;
      }
    }
  }

  Long getUserId(String username, String apiKey) {
    if (username == null || username.trim().isEmpty()) {
      throw new IllegalArgumentException("username must be set");
    }
    if (apiKey == null || apiKey.trim().isEmpty()) {
      throw new IllegalArgumentException("apiKey must be set");
    }
    if (sqlSessionFactory == null) {
      throw new AuthException("This is the endpoint for the basic version of LanguageTool. " +
        "When using 'username' and 'apiKey' to access the premium version, use api.languagetoolplus.com instead.");
    }
    try {
      Long value = dbLoggingCache.get(String.format("user_%s_%s", username, apiKey), () -> {
        try (SqlSession session = sqlSessionFactory.openSession()) {
          Map<Object, Object> map = new HashMap<>();
          map.put("username", username);
          map.put("apiKey", apiKey);
          Long id = session.selectOne("org.languagetool.server.UserDictMapper.getUserIdByApiKey", map);
          if (id == null) {
            return -1L;
          }

View on GitHub (pinned to 2e990059ce)

Solutions

  1. Provide a non-empty username alongside the apiKey in the request (both fields are required for API-key auth).
  2. Fix client parameter naming so the username is actually transmitted (e.g. use 'username' field, not 'user'/'email').
  3. Add caller-side validation that trims and rejects empty username before calling the API.

Example fix

// before
POST /v2/user { "apiKey": "abc" } // IllegalArgumentException: username must be set
// after
POST /v2/user { "username": "bob", "apiKey": "abc" }
Defensive patterns

Strategy: validation

Validate before calling

if (username == null || username.trim().isEmpty()) {
  throw new IllegalArgumentException("username must be set before calling the API");
}

Type guard

boolean isValidUsername(String u) { return u != null && !u.trim().isEmpty(); }

Try / catch

try {
  Long userId = db.getUserId(username, apiKey);
} catch (IllegalArgumentException e) {
  // report missing/blank username to caller
}

Prevention

When it happens

Trigger: Calling getUserId (directly or via userId()/getUserInfoWithApiKey paths, e.g. the /v2/user or authentication endpoints) with username missing/null/blank while an apiKey is supplied.

Common situations: Client sends apiKey but omits username; form/API field named differently (e.g. only 'email' or 'token') so username arrives empty; code reading an unset config property for the username.

Understand the failure class

Background: "missing required argument" and "the following required arguments were not provided": what required-argument errors mean and how to fix them — this error's family across 20 libraries.

Related errors


AI-assisted analysis of languagetool-org/languagetool@2e990059ce (2026-09-06). Data as JSON: /api/errors/673e79de0908691c. Report an issue: GitHub.