没有不值得去解决的问题,也没有不值得去学习的技术!

WordPress SlyTranslate + GLM-5.2 Long-Text Translation: Investigating the False Failure of invalid_translation_runaway_output

【图 5,54 个代码块精确匹配、差异数量为 0】

When building an automated English translation workflow for my WordPress blog, I wanted to solve one core problem:

Letting the AI read the full context of an article in a single pass to achieve English quality closer to a complete human re-translation, while preserving Gutenberg blocks, code blocks, HTML tags, and link structures.

SlyTranslate’s original block translation mechanism prioritizes compatibility and stability by splitting Gutenberg content into multiple fragments and calling the model separately for each. For typical short articles, this approach is usually acceptable. However, for long articles containing numerous technical terms, contextual dependencies, and code blocks, chunked translation often leads to inconsistent terminology, disjointed sentences, and a lack of coherence across sections.

Therefore, instead of continuing to increase the chunk character limit, this test adhered to the following approach:

  • Translate the title separately;
  • Translate the excerpt separately;
  • Call GLM-5.2 only once for the main content;
  • Replace code blocks and inline code with placeholders beforehand;
  • Restore the original Gutenberg content after translation;
  • Save to the Polylang English article only after all validations pass.

Ultimately, the single-pass call for the main content succeeded. However, the backend still returned an error that appeared quite severe:

JSON
{
    "code": "invalid_translation_runaway_output",
    "message": "The translated output is far longer than the source text, indicating the model entered a runaway generation loop or appended hallucinated content.",
    "data": null
}

After tracing the execution path, I discovered that the model had not actually run away with its generation. Instead, after the custom single-pass translation completed, SlyTranslate’s original translation workflow executed a second time.

This article documents the complete troubleshooting process, from “model output anomaly” to “duplicate REST route execution.”

1. Complexity of the Test Article

This test used a real, long WordPress technical article:

Plaintext
Article ID: 19372
Content character count: 232908
Content size: 242338 Bytes
Top-level Gutenberg blocks: 463
Code Block Pro blocks: 54

The article primarily documents the link repair process across WordPress, Polylang, W3 Total Cache, WPCode, Nginx, and a multi-domain environment.

The 54 Code Block Pro blocks contain not only commands and configurations but also complete:

  • textarea raw code;
  • pre.shiki highlighted HTML;
  • Gutenberg block comments;
  • JSON block attributes;
  • Paths, domains, and URLs;
  • Bash, PHP, JavaScript, and plain text content.

Feeding the entire Gutenberg source code directly to the model for translation would not only waste substantial context but also risk rewriting Chinese comments, HTML attributes, or Shiki highlighting structures within the code blocks.

Therefore, a single-pass translation does not mean sending the raw article to the model unprocessed.

2. Basic Concept of the Single-Call Approach

In this approach, I first used SlyTranslate’s client-side translation workflow to read the article and split the content into three main translation units:

Plaintext
title
content
excerpt

Specifically:

  • The title is called separately as short text;
  • The excerpt is called separately as short text;
  • The main content, after protection, calls GLM-5.2 only once.

Complete code blocks are first replaced with block placeholders, while inline code, URLs, and other content that should not be translated use inline placeholders.

When the main content is sent to the model, it primarily sees standard paragraphs, headings, lists, and placeholders, rather than a complete code structure spanning over 200,000 characters.

The main parameters used during the content call phase are:

Plaintext
model: glm-5.2
thinking: disabled
max_tokens: 32768
timeout: 600 seconds

I also added a single-request guard: during the content translation phase, only one Zhipu /chat/completions request is allowed. Any additional content requests should be treated as process anomalies rather than automatic retries.

[Figure 1, Selecting GLM-5.2 in the SlyTranslate backend and starting translation]
[Figure 1, Selecting GLM-5.2 in the SlyTranslate backend and starting translation]

3. Why I Did Not Continue with Chunk Parameter Optimization

During troubleshooting, I briefly considered raising SlyTranslate’s content chunk character limit to:

Plaintext
60000

On the surface, this would reduce the number of chunks and increase the context length per request.

However, further analysis revealed that this article contains 54 Code Block Pro blocks. SlyTranslate’s original workflow treats non-translatable code blocks as interval boundaries, so even raising the character limit to 60000 would not merge the text before and after the code blocks into a complete context.

The result would still likely require dozens of API calls.

While this type of parameter optimization might improve stability, it cannot truly achieve the original goal:

Letting the model see the logical relationships of the entire article and achieving quality as close as possible to a complete human re-translation.

Therefore, I ultimately decided to continue troubleshooting the single-pass content call instead of reverting to the native chunking workflow.

4. Backend Still Reports Error After Single Call Succeeds

After the test began, the backend waited for about ten minutes and ultimately returned:

Plaintext
invalid_translation_runaway_output

The initial, most straightforward assumptions were:

  • The English output was longer than the Chinese content;
  • The model might have generated extra explanations;
  • The output length ratio validation was too strict;
  • After placeholder restoration, the content length triggered SlyTranslate’s runaway validation.

But these hypotheses had an obvious flaw:

The custom workflow did not generate the expected error diagnostic file.

If the error had occurred during our own content output validation phase, it should have logged:

  • Original output length;
  • Placeholder count;
  • Missing or duplicate placeholders;
  • Output fragments;
  • Custom error source.

The actual situation was that the backend directly returned SlyTranslate’s original error code.

This indicated that the error likely did not originate from the single call itself.

5. Adding Execution Path Tracing

To determine exactly which step the request reached, I added a logging-only, non-intrusive execution trace layer to the MU Plugin.

The diagnostics included:

  • Whether the REST route was seen;
  • Whether the custom REST interception logic was entered;
  • Article ID and model name;
  • How many times the title, excerpt, and content were executed respectively;
  • How many Zhipu requests were actually sent during the content phase;
  • Whether prepare_single() succeeded;
  • Whether apply_single() succeeded;
  • Whether the error occurred within or after the custom workflow.

The command to read the execution trace was:

Bash
cd /data/wwwroot/www.shuijingwanwq.com
php /tmp/swq-read-glm52-execution-trace.php

The key results were as follows:

Plaintext
rest_route_seen
rest_input_resolved | post_id=19372 | model_slug=glm-5.2
rest_intercept_entered
job_started | post_id=19372

prepare_succeeded
units=[
    title:title:54,
    content:content:232908,
    excerpt:excerpt:254
]

unit_started | field=content | source_chars=232908
content_raw_started

full_article_request_counted | request_count=1

content_raw_finished
output_chars=33292
result_type=string
error_code=null
request_count=1
model=glm-5.2

unit_finished
field=content
output_chars=243100
result_type=string
error_code=null

apply_started | translation_count=3
apply_finished | result_type=array | error_code=null
rest_intercept_returned | result_type=array | error_code=null

These logs proved several crucial facts:

  1. The content indeed made only one request to GLM-5.2;
  2. The model successfully returned an English payload of about 33,000 characters;
  3. After restoring the code blocks, the complete content was 243,100 characters;
  4. The title, content, and excerpt all returned no errors;
  5. apply_single() executed successfully;
  6. The custom REST workflow returned normal results.

In other words, before the backend error appeared, the article translation and saving had actually already completed.

[Figure 2, Results of request_count=1 and apply_finished in the execution trace]
[Figure 2, Results of request_count=1 and apply_finished in the execution trace]

6. The Real Anomaly Occurred After the Custom Workflow Returned

The most critical part of the execution trace was not the preceding success logs, but rather:

Plaintext
rest_intercept_returned

After this, a large number of new Zhipu requests still appeared:

Plaintext
http_request_args_before | active=no
http_request_args_after  | active=no
pre_http_request_seen    | active=no

The input length for these requests was only about 1500–2300 characters, closely resembling SlyTranslate’s native translation of small Gutenberg blocks.

And active=no indicated that they were no longer in the custom single-pass content phase.

This meant the actual execution sequence was:

Plaintext
Custom single-pass translation
→ Successfully saved English article
→ Custom callback returned
→ SlyTranslate original REST callback continued execution
→ Native chunked translation started
→ A chunk triggered runaway_output
→ Backend ultimately displayed failure

Therefore, the error seen in the backend was not the result of the first single call, but the result of the second native workflow.

This also explains why:

  • The single content request log showed success;
  • The updated English article already existed in the database;
  • The page still displayed invalid_translation_runaway_output;
  • Dozens of small requests appeared after the error.

7. The Problem Lay in the REST Interception Hook

The original custom interception logic was registered at:

PHP
rest_request_before_callbacks

This position allows requests to be inspected or processed before the REST callback executes. However, although this implementation returned the custom translation result, it did not actually prevent SlyTranslate’s route from continuing to execute its original callback.

As a result, the same REST request effectively executed two workflows.

The fix was to change the interception entry point to:

PHP
rest_dispatch_request

The conceptual change was as follows:

Plaintext
// Original interception point
rest_request_before_callbacks

// Fixed interception point
rest_dispatch_request

At the new dispatch entry point, as long as the custom single-pass translation returns a non-empty result, the WordPress REST Server uses that result directly and no longer continues to invoke SlyTranslate’s original callback.

This modification only adjusted the REST dispatch location and did not change:

  • The single-pass content call logic;
  • GLM-5.2 request parameters;
  • Title and excerpt translation;
  • Typed tokens placeholders;
  • Code Block Pro protection;
  • prepare_single();
  • apply_single();
  • Article saving method.

After installing the fixed version, a read-only check confirmed:

Plaintext
mu_class_loaded=yes
dispatch_override_registered=yes
old_before_callback_hook_removed=yes
http_tuning_registered=yes
single_request_guard_registered=yes
zhipu_api_called=no
database_modified=no

This indicated that:

  • The new dispatch hook was registered;
  • The old hook was removed;
  • The GLM-5.2 parameter adjustments remained effective;
  • The single-request guard for content was still in place;
  • The check process did not call the API or modify the database.
[Figure 3, Dispatch Fix Check all showing yes]
[Figure 3, Dispatch Fix Check all showing yes]

8. The English Article Was Actually Saved Successfully

Since the execution trace already showed:

Plaintext
apply_finished

I did not immediately click Translate Now again, but instead first queried the status of the Polylang English article.

The query results were:

Plaintext
source_id=19372
target_id=19426
status=publish
modified=2026-07-15 16:22:00

title=WordPress Polylang English Subdomain Migration Links Still Pointing to Chinese Site: Complete Fix for Category Dropdowns, Breadcrumbs, and Block Templates

content_chars=243100
excerpt_chars=813
swq_tokens=no

This further proved that:

Although the backend showed a translation failure, the English article generated by the single call had already been saved and published.

This situation can easily mislead judgment when troubleshooting automated tasks.

If I had only looked at the frontend error message, I might have continued tweaking model parameters, output ratios, or prompts, potentially overwriting the successfully generated translation.

[Figure 4, Publish status and title of English article ID 19426]
[Figure 4, Publish status and title of English article ID 19426]

9. Verifying Gutenberg and Code Block Pro Structure

A successful article save does not guarantee that the structure is safe.

Next, I compared the counts between the Chinese source and the English article:

Plaintext
========== source ==========
content_chars=232908
code_block_pro=108
textarea_tags=54
shiki_pre_tags=54
gutenberg_open_comments=304
gutenberg_close_comments=304
swq_tokens=no

========== target ==========
content_chars=243100
code_block_pro=108
textarea_tags=54
shiki_pre_tags=54
gutenberg_open_comments=304
gutenberg_close_comments=304
swq_tokens=no

code_block_pro=108 occurs because each Code Block Pro block name appears in both its opening and closing comments, so the actual number of blocks remains 54.

The results showed:

  • Consistent count of Gutenberg opening comments;
  • Consistent count of Gutenberg closing comments;
  • All 54 textarea retained;
  • All 54 Shiki pre retained;
  • No SWQ placeholders left behind.

Following that, I extracted the Code Block Pro blocks from both the Chinese and English articles one by one and performed an exact comparison using their serialized content:

Plaintext
source_code_blocks=54
target_code_blocks=54
exact_matches=54
mismatch_count=0
mismatch_indexes=none

In other words, all 54 code blocks were verbatim identical.

The code, commands, paths, URLs, JSON attributes, HTML tags, and Shiki highlighting content were all unmodified.

[Figure 5, 54 code blocks exactly matched, difference count is 0]
[Figure 5, 54 code blocks exactly matched, difference count is 0]

10. Checking for Missing Translations

Finally, I removed all Code Block Pro content and then checked for Chinese characters in the title, excerpt, and standard body text.

The results were:

Plaintext
title_chinese_chars=0
excerpt_chinese_chars=0
content_chinese_chars_outside_code=0

========== Chinese snippets outside code ==========
none

This indicated that:

  • The English title had no residual Chinese;
  • The English excerpt had no residual Chinese;
  • No missing translations in the text outside code blocks;
  • Chinese comments within code blocks were preserved exactly as per the protection rules.

At this point, it could be confirmed that this single call technically achieved three goals:

  1. The model was called only once for the content;
  2. The Gutenberg and code block structures were intact;
  3. There were no missing Chinese translations in the standard body text.

11. Preliminary Translation Quality Assessment

I then conducted a manual evaluation of the generated complete English text.

The overall score for this single call was approximately:

Plaintext
85 / 100

The previous score for SlyTranslate’s native chunked translation was approximately:

Plaintext
76 / 100

The most notable improvement this time was in contextual understanding and technical term differentiation.

For example, the term “固定链接” (fixed link) carries different meanings in different contexts throughout the Chinese article.

When referring to WordPress URL rules, the model translated it as:

Plaintext
permalink rules

When referring to fixed addresses hardcoded into navigation or blocks, the model translated it as:

Plaintext
hardcoded links

This is more accurate than mechanically translating all instances of “固定链接” uniformly as permalink.

The current translation also consistently distinguishes between:

  • Dynamically generated links;
  • Hardcoded links saved in blocks;
  • Blog Homepage template;
  • All Archives template;
  • Cloudflare page cache;
  • W3 Total Cache Object Cache;
  • Origin server responses versus actual browser interactions.

This demonstrates that the single-pass content call genuinely improved cross-section terminology consistency and contextual coherence. The translation can now use permalink rules and hardcoded links appropriately based on the specific context.

However, there are still some details requiring further optimization.

For instance, some sentences still bear the structural marks of Chinese paragraph splitting:

Plaintext
Ultimately returning a 404.

And:

Plaintext
Which further redirects to the official category archive:
Plaintext
And returns a 200 normally.

While understandable, for an international technical blog, a more natural approach would be to merge these into complete English sentences.

Additionally, English double quotes in some image alt attributes were not escaped:

HTML
alt="【Figure 1, Categories List block and "Display as dropdown" setting in the theme editor】"

This could affect the HTML attribute structure. While this issue did not break the Gutenberg block count, it indicates that image attributes also require stricter protection, much like code blocks.

These are translation naturalness and HTML attribute protection issues to be addressed in the next phase, and they do not affect the conclusion on whether the “single-pass content call” is viable.

12. Conclusions from This Troubleshooting

1. Error Codes Do Not Necessarily Originate from the Model Call You Are Currently Viewing

When multiple execution paths exist within a single REST request, the ultimately returned error may come from the second workflow.

You cannot solely base your conclusion on:

Plaintext
invalid_translation_runaway_output

to assert that the first GLM-5.2 call ran away.

You must correlate it with:

  • API request counts;
  • Model invocation phases;
  • apply_single() results;
  • Database article status;
  • REST callback execution order.

2. “Single Content Call” Must Be Verified at the HTTP Layer

Designing the code to make a single call does not guarantee that only one call actually occurs at runtime.

This time, it was only by observing:

Plaintext
full_article_request_counted | request_count=1

alongside the subsequent flurry of active=no requests, that I could distinguish between:

  • The custom single-pass content call;
  • SlyTranslate’s native chunked calls.

3. A Backend Failure Does Not Mean the Database Was Not Saved

In this instance, the English article was successfully written and published, but the error from the second workflow overwrote the prior success result.

Therefore, before re-translating or overwriting an article, you should first check:

  • The corresponding Polylang English article ID;
  • Modification time;
  • Title and content length;
  • Whether any placeholders remain.

4. Translation Quality and Structural Safety Are Two Independent Issues

The structural validation results this time were excellent:

Plaintext
All 54 code blocks verbatim identical
304 pairs of Gutenberg opening and closing comments perfectly matched
Residual Chinese outside code blocks is 0

However, there is still room for improvement in English naturalness.

Therefore, subsequent optimizations should be handled separately for:

  • Translation quality;
  • HTML attribute safety;
  • Title and excerpt naturalness;
  • Gutenberg and code block integrity.

Just because the block structure is correct does not mean the English language quality has reached its final standard.

13. Conclusion for the Current Phase

Through this troubleshooting, it can be confirmed that:

The SlyTranslate + GLM-5.2 single-pass content call approach for long WordPress articles is viable.

This effort successfully achieved:

  • Processing a 230,000-character WordPress technical article;
  • Complete protection of 54 Code Block Pro blocks;
  • A single GLM-5.2 call for the main content;
  • Successful saving of the English article to Polylang;
  • Consistent Gutenberg structure counts;
  • Verbatim identical code blocks;
  • No missing Chinese translations in the standard body text;
  • Translation quality significantly higher than the native chunking workflow.

The previous invalid_translation_runaway_output was not a failure of the single-pass content call, but rather an incorrect REST interception location that caused SlyTranslate’s original callback to execute again after the custom workflow completed.

The dispatch entry point has now been changed from:

Plaintext
rest_request_before_callbacks

to:

Plaintext
rest_dispatch_request

and verified via hook registration checks.

Next, a full regression test using other articles is still needed to ensure that the backend can run from clicking Translate Now all the way to returning a success message without entering the native chunking workflow again.

As for English sentence naturalness, title compression, excerpt optimization, and image attribute protection, these can be refined in the next phase.

At least for now, the most critical step is complete:

Instead of reverting to dozens of chunked calls for stability, we retain the full context and use a single content request to achieve better English translation quality.

系列导航

需要长期技术维护或远程问题排查?

我是拥有 15+ 年经验的 PHP / Go 后端工程师,长期关注已有系统维护、Bug 修复、性能优化、服务器排查、WordPress 网站维护和小功能迭代。

如果你的项目遇到以下情况,可以先从一次小问题排查开始合作:

  • ✅ PHP / Laravel / Yii2 老项目无人维护
  • ✅ Go / Gin 后端接口需要排查或优化
  • ✅ WordPress 网站访问慢、报错或插件冲突
  • ✅ Nginx / MySQL / Redis / Linux 服务器异常
  • ✅ CDN / Cloudflare / DNS / HTTPS 配置问题
  • ✅ 需要长期远程技术支持或兼职维护

更多介绍请查看:关于我 & 合作

微信:13980074657
邮箱:shuijingwanwq@gmail.com
Telegram:@shuijingwan
GitHub:https://github.com/shuijingwan

评论

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

这个站点使用 Akismet 来减少垃圾评论。了解你的评论数据如何被处理