{"record":{"id":"60190dab0e5e5694","repo":"languagetool-org/languagetool","slug":"your-text-exceeds-the-limit-of-maxtextlength-cha","errorCode":null,"errorMessage":"Your text exceeds the limit of {maxTextLength} characters (it's {length} characters). Please submit a shorter text.","messagePattern":"Your text exceeds the limit of (.+?) characters \\(it's (.+?) characters\\)\\. Please submit a shorter text\\.","errorType":"http","errorClass":"TextTooLongException","httpStatus":400,"severity":"error","filePath":"languagetool-server/src/main/java/org/languagetool/server/TextChecker.java","lineNumber":414,"sourceCode":"    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);\n        httpExchange.getResponseBody().write(response.getBytes(ENCODING));\n        String message = \"Blocked request from uid:\" + userId + \" because user limit is reached: \";\n        message += \"limit = \" + limits.getRequestsPerDay() + \", mode = \" + limits.getLimitEnforcementMode() + \". \";\n        message += \"Access from \" + remoteAddress + \", \";\n        message += \"HTTP user agent: \" + userAgent + \", \";\n        message += \"User agent param: \" + params.get(\"useragent\") + \", \";\n        message += \"Referrer: \" + referrer + \", \";\n        message += \"language: \" + params.get(\"language\") + \", \";\n        message += \"h: \" + reqCounter.getHandleCount() + \", \";","sourceCodeStart":396,"sourceCodeEnd":432,"githubUrl":"https://github.com/languagetool-org/languagetool/blob/2e990059ce67d5e2a0f7f7ca5d31160c6709df4b/languagetool-server/src/main/java/org/languagetool/server/TextChecker.java#L396-L432","documentation":"LanguageTool server enforces a per-request maximum text length (limits.getMaxTextLength(), default smaller for anonymous users). When the submitted plain-text length exceeds that limit it logs a MAX_TEXT_SIZE metric and throws TextTooLongException (HTTP 413-style) telling the client to submit a shorter text.","triggerScenarios":"POSTing a text (or data-annotated text) to /v2/check whose getPlainText().length() exceeds the configured limit — e.g. default 20KB anonymous limit or a custom maxTextLength server option — from checkText or its test callers.","commonSituations":"Pasting whole documents or books into the API, uploading large files, or anonymous clients hitting the smaller anonymous limit while assuming the authenticated (premium) limit applies.","solutions":["Split the text into chunks below the limit and check each chunk separately, merging results","Authenticate with a premium account whose configured maxTextLength is higher","Raise the server's maxTextLength configuration option if you operate the server","Strip unnecessary content (markup, quotes) before submission to reduce length"],"exampleFix":"// before\ncurl -d \"text=$(cat bigdoc.txt)\" -d language=en-US http://server/v2/check\n// after\nsplit -b 19000 bigdoc.txt part_; for f in part_*; do curl -d \"text=$(cat $f)\" -d language=en-US http://server/v2/check; done","handlingStrategy":"validation","validationCode":"const MAX_LEN = 20000; // anonymous default; use your account's limit\nif (text.length > MAX_LEN) {\n  return chunkText(text, MAX_LEN).map(checkChunk);\n}","typeGuard":null,"tryCatchPattern":"try {\n  return await check(text);\n} catch (e) {\n  if (e.status === 413 || /exceeds the limit/.test(e.message)) {\n    return chunkAndCheck(text, parseLimitFromMessage(e.message));\n  }\n  throw e;\n}","preventionTips":["Check text.length before each request and chunk proactively","Keep chunks well under the limit (e.g. 19KB) to account for overhead","Authenticate to get the larger limit when checking long documents","Remember the limit counts plain-text characters, not bytes or markup"],"tags":["payload-size","http-413","languagetool-server"],"backgroundTag":"payload-too-large","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"}