{"record":{"id":"f011a3395bf4b738","repo":"languagetool-org/languagetool","slug":"anonymous-access-is-prohibited-on-this-server-ple","errorCode":null,"errorMessage":"Anonymous access is prohibited on this server, please provide authentication.","messagePattern":"Anonymous access is prohibited on this server, please provide authentication\\.","errorType":"http","errorClass":"AuthException","httpStatus":401,"severity":"error","filePath":"languagetool-server/src/main/java/org/languagetool/server/TextChecker.java","lineNumber":405,"sourceCode":"      httpExchange.getResponseBody().write(response.getBytes(ENCODING));\n      return;\n    }\n\n    String requestId = httpExchange.getRequestHeaders().getFirst(\"X-Request-ID\");\n\n    // logging information\n    String agent = params.get(\"useragent\") != null ? params.get(\"useragent\") : \"-\";\n    Long agentId = null, userId = null;\n    if (databaseLogger.isLogging()) {\n      DatabaseAccess db = DatabaseAccess.getInstance();\n      agentId = db.getOrCreateClientId(params.get(\"useragent\"));\n      userId = limits.getPremiumUid();\n    }\n    String referrer = httpExchange.getRequestHeaders().getFirst(\"Referer\");\n    String userAgent = httpExchange.getRequestHeaders().getFirst(\"User-Agent\");\n\n    if (!config.isAnonymousAccessAllowed() && limits.getPremiumUid() == null) {\n      throw new AuthException(\"Anonymous access is prohibited on this server, please provide authentication.\");\n    }\n\n    int length = aText.getPlainText().length();\n    if (\"true\".equals(params.get(\"languageChanged\"))) {\n      log.info(\"languageChanged to \" + params.get(\"language\") + \" for text with length \" + aText.getPlainText().trim().length());\n    }\n    if (length > limits.getMaxTextLength()) {\n      ServerMetricsCollector.getInstance().logRequestError(ServerMetricsCollector.RequestErrorType.MAX_TEXT_SIZE);\n      throw new TextTooLongException(\"Your text exceeds the limit of \" + limits.getMaxTextLength() +\n              \" characters (it's \" + length + \" characters). Please submit a shorter text.\");\n    }\n    // static because we can't rely on errorRequestLimiter, null when timeoutRequestLimit option not set\n    if (!config.isLocalApiMode()) {\n      try {\n        RequestLimiter.checkUserLimit(referrer, userAgent, limits);\n      } catch (TooManyRequestsException e) {\n        String response = \"Error: Access denied: \" + e.getMessage();\n        httpExchange.sendResponseHeaders(HttpURLConnection.HTTP_FORBIDDEN, response.getBytes(ENCODING).length);","sourceCodeStart":387,"sourceCodeEnd":423,"githubUrl":"https://github.com/languagetool-org/languagetool/blob/2e990059ce67d5e2a0f7f7ca5d31160c6709df4b/languagetool-server/src/main/java/org/languagetool/server/TextChecker.java#L387-L423","documentation":"The server is configured with a limit (e.g. -X 'maximum text length' / anonymousAccess disallowed) that forbids unauthenticated requests. checkText throws AuthException when no premium UID (from authentication) is supplied and the config disallows anonymous access.","triggerScenarios":"POSTing to /v2/check (directly or via testPipelineCreatedAndUsed/testJSONP-style callers) without valid credentials (username/password, API token) on a server started without the anonymousAccess option, so limits.getPremiumUid() is null and config.isAnonymousAccessAllowed() is false.","commonSituations":"Running a private LanguageTool server with authentication enforced but calling it from a script or browser app that never sends the Basic auth header; CI tests hitting a locked-down production instance.","solutions":["Send authentication with the request (username/password/token parameters or Basic auth header) to obtain a premium UID","Start the server with anonymous access allowed (e.g. do not set the 'no anonymous' option / set the option permitting public access) if this is intended to be a public server","Point the client at a server instance whose access policy matches your use case"],"exampleFix":"// before\ncurl -d text=... -d language=en-US http://server/v2/check\n// after\ncurl -u user:token -d text=... -d language=en-US http://server/v2/check","handlingStrategy":"validation","validationCode":"if (!credentials.username || !credentials.token) {\n  throw new Error('This server requires authentication; supply username/token before calling /v2/check');\n}","typeGuard":"function hasAuth(c) {\n  return c != null && typeof c === 'object' && typeof c.username === 'string' && c.username.length > 0 && typeof c.token === 'string' && c.token.length > 0;\n}","tryCatchPattern":"try {\n  return await check(text, { auth });\n} catch (e) {\n  if (e.status === 401 || /Anonymous access is prohibited/.test(e.message)) {\n    throw new AuthRequiredError('Configure credentials for this LanguageTool server');\n  }\n  throw e;\n}","preventionTips":["Check the server's access policy (anonymous allowed?) before deploying clients","Always attach Basic auth/credentials for private instances","Distinguish public api.languagetool.org from self-hosted restricted servers in config","Test auth flow in CI against a locked-down instance"],"tags":["authentication","http-401","languagetool-server"],"backgroundTag":"authentication-required","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"}