{"record":{"id":"4c9e02809bb76255","repo":"fishaudio/fish-speech","slug":"text-is-too-long-max-length-is-app-state-max-tex","errorCode":null,"errorMessage":"Text is too long, max length is {app_state.max_text_length}","messagePattern":"Text is too long, max length is (.+?)","errorType":"http","errorClass":"HTTPException","httpStatus":400,"severity":"warning","filePath":"tools/server/views.py","lineNumber":160,"sourceCode":"            HTTPStatus.INTERNAL_SERVER_ERROR, content=\"Failed to decode tokens to audio\"\n        )\n\n\n@routes.http.post(\"/v1/tts\")\nasync def tts(req: Annotated[ServeTTSRequest, Body(exclusive=True)]):\n    \"\"\"\n    Generate speech from text using TTS model.\n    \"\"\"\n    try:\n        # Get the model from the app\n        app_state = request.app.state\n        model_manager: ModelManager = app_state.model_manager\n        engine = model_manager.tts_inference_engine\n        sample_rate = engine.decoder_model.sample_rate\n\n        # Check if the text is too long\n        if app_state.max_text_length > 0 and len(req.text) > app_state.max_text_length:\n            raise HTTPException(\n                HTTPStatus.BAD_REQUEST,\n                content=f\"Text is too long, max length is {app_state.max_text_length}\",\n            )\n\n        # Check if streaming is enabled\n        if req.streaming and req.format != \"wav\":\n            raise HTTPException(\n                HTTPStatus.BAD_REQUEST,\n                content=\"Streaming only supports WAV format\",\n            )\n\n        # Perform TTS\n        if req.streaming:\n            return StreamResponse(\n                iterable=inference_async(req, engine),\n                headers={\n                    \"Content-Disposition\": f\"attachment; filename=audio.{req.format}\",\n                },","sourceCodeStart":142,"sourceCodeEnd":178,"githubUrl":"https://github.com/fishaudio/fish-speech/blob/befe4001745417f8c42131739d862b8a6fdbd15a/tools/server/views.py#L142-L178","documentation":"Raised by the TTS endpoint when the submitted text exceeds the server-configured max_text_length limit. It is an HTTP 400 BAD_REQUEST returned before any model inference runs. The limit exists to bound GPU memory usage and generation time.","triggerScenarios":"POST /v1/tts (or OpenAI-compatible /v1/audio/speech) with req.text longer than app_state.max_text_length (when max_text_length > 0). Long documents, unsubtitled full articles, or clients not splitting text trigger it.","commonSituations":"Default max_text_length too low for batch narration workloads; clients pasting entire articles; changing max_text_length config but not restarting; misunderstanding that the limit counts characters, not tokens.","solutions":["Split the text into chunks under max_text_length and synthesize each separately, concatenating the WAV/PCM output.","Increase max_text_length in the server configuration (e.g. config file or KOKORO_TTS_MAX_TEXT_LENGTH env var) if your hardware allows longer generations.","Set max_text_length to 0 to disable the limit entirely (only if you accept unbounded generation cost)."],"exampleFix":"# before\nresp = requests.post(url, json={\"text\": long_article})\n\n# after\nfor chunk in chunks(long_article, max_len - 1):\n    resp = requests.post(url, json={\"text\": chunk})\n    ...","handlingStrategy":"validation","validationCode":"max_len = get_server_config().max_text_length\ntext = \"...\"\nassert max_len == 0 or len(text) <= max_len, f\"text {len(text)} > {max_len}\"","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Fetch or mirror max_text_length in the client config","Chunk long documents to just under the limit and concatenate WAV output"],"tags":["tts","input-validation","text-length","http-400"],"backgroundTag":"request-payload-too-large","analyzedSha":"befe4001745417f8c42131739d862b8a6fdbd15a","analyzedAt":"2026-08-27T21:31:45.703Z","schemaVersion":2},"datasetVersion":"2026-08-28T00:17:15.603Z"}