<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: xn</title>
    <description>The latest articles on DEV Community by xn (@xbstack).</description>
    <link>https://dev.to/xbstack</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4041503%2F9c739d89-3716-4032-abe2-f2a93ffb32fd.png</url>
      <title>DEV Community: xn</title>
      <link>https://dev.to/xbstack</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/xbstack"/>
    <language>en</language>
    <item>
      <title>Gemini 3.8 Flash vs 3.7 Flash: Same Price, Different Agent Cost?</title>
      <dc:creator>xn</dc:creator>
      <pubDate>Thu, 03 Sep 2026 05:46:19 +0000</pubDate>
      <link>https://dev.to/xbstack/gemini-38-flash-vs-37-flash-same-price-different-agent-cost-2cde</link>
      <guid>https://dev.to/xbstack/gemini-38-flash-vs-37-flash-same-price-different-agent-cost-2cde</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;A production-focused update based on a real project: Gemini 3.8 Flash vs 3.7 Flash: compare pricing, 1M context, thinking levels, coding/agent changes, migration steps, and why eq…&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;The most important Gemini 3.8 Flash vs 3.7 Flash distinction is not the API rate card. The two models currently have the same token prices, but that does not mean they will cost the same to finish the same job.&lt;/strong&gt; Google released Gemini 3.8 Flash on September 2, 2026 and kept the same introductory input/output rates as 3.7 Flash. At the same time, Google explicitly says 3.8 “works harder” on complex tasks: it can take more reasoning steps, call tools iteratively, and verify its work, which can increase token use on longer agentic runs.&lt;/p&gt;

&lt;p&gt;If you are searching for &lt;strong&gt;Gemini 3.8 Flash vs 3.7 Flash, 3.8 pricing, the API model ID, whether coding agents should upgrade, or why the same token price can still produce a higher bill&lt;/strong&gt;, the practical answer is: &lt;strong&gt;3.8 is a stronger migration candidate for long-horizon software engineering and multi-tool agents; stable, latency-sensitive and efficiency-first workloads do not need to leave 3.7 just because a newer model exists.&lt;/strong&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Evidence boundary: this page is an official-evidence migration and model-selection guide, not an XBSTACK API A/B benchmark. We have not yet run 3.8 and 3.7 through the same repository tasks, prompts, thinking levels and tool permissions in a repeatable test matrix, so Google benchmark results remain Google results rather than “our tests.”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Gemini 3.8 Flash vs 3.7 Flash at a glance
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Item&lt;/th&gt;
&lt;th&gt;Gemini 3.8 Flash&lt;/th&gt;
&lt;th&gt;Gemini 3.7 Flash&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Model ID&lt;/td&gt;
&lt;td&gt;&lt;code&gt;gemini-3.8-flash&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;gemini-3.7-flash&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Release status&lt;/td&gt;
&lt;td&gt;GA&lt;/td&gt;
&lt;td&gt;GA&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Context window&lt;/td&gt;
&lt;td&gt;1M tokens&lt;/td&gt;
&lt;td&gt;1M tokens&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Max output&lt;/td&gt;
&lt;td&gt;64K tokens&lt;/td&gt;
&lt;td&gt;64K tokens&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Thinking levels&lt;/td&gt;
&lt;td&gt;low / medium / high&lt;/td&gt;
&lt;td&gt;low / medium / high&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Default thinking&lt;/td&gt;
&lt;td&gt;medium&lt;/td&gt;
&lt;td&gt;medium&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Input price through 2026-12-31&lt;/td&gt;
&lt;td&gt;$0.75 / 1M tokens&lt;/td&gt;
&lt;td&gt;$0.75 / 1M tokens&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Output price through 2026-12-31&lt;/td&gt;
&lt;td&gt;$3.75 / 1M tokens&lt;/td&gt;
&lt;td&gt;$3.75 / 1M tokens&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Primary positioning&lt;/td&gt;
&lt;td&gt;Long-horizon software engineering, autonomous agents, complex enterprise workflows&lt;/td&gt;
&lt;td&gt;Efficient coding, agents and reliable multi-step execution&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Still supported by Google&lt;/td&gt;
&lt;td&gt;Current flagship Flash&lt;/td&gt;
&lt;td&gt;Yes, fully supported&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Google’s current pricing documentation also gives a date for the next step: the introductory rates run through &lt;strong&gt;December 31, 2026&lt;/strong&gt;. Starting &lt;strong&gt;January 1, 2027&lt;/strong&gt;, the listed standard rates become $1.50/M input and $7.50/M output tokens.&lt;/p&gt;

&lt;p&gt;That means the obvious specification table is not where the real decision lives. The bigger difference is how the model spends reasoning and tool-use budget inside a task.&lt;/p&gt;

&lt;p&gt;Official source: &lt;a href="https://ai.google.dev/gemini-api/docs/latest-model" rel="noopener noreferrer"&gt;Gemini API — What’s new in Gemini 3.8 Flash&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Why can Gemini 3.8 cost more per task if the token rate is identical?
&lt;/h2&gt;

&lt;p&gt;Google is unusually explicit about this trade-off. On difficult tasks, 3.8 may take smaller reasoning steps, call tools multiple times and verify intermediate work. At higher effort levels, this can increase token consumption.&lt;/p&gt;

&lt;p&gt;So a production model-cost calculation should not stop at:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;input rate + output rate&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;A better unit is:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;task completion cost = input tokens + output/thinking tokens + extra tool-call turns + retries/failures + human correction time&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;If 3.8 consumes more tokens but significantly reduces failed loops, rework and manual correction, it may still reduce the cost of completing the job. If the job is simple and already succeeds in one pass, extra reasoning can simply become extra spend.&lt;/p&gt;

&lt;p&gt;That is why Google presents both paths as valid:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;use 3.8 with medium/high effort for hard workflows;&lt;/li&gt;
&lt;li&gt;lower the effort for efficiency-sensitive work, or keep using 3.7 Flash.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For XBSTACK, that is the key reason we will not translate “same price” into “same task cost” without a controlled workload test.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/..%2F..%2F..%2Fassets%2Fuploads%2Fgemini-3-8-flash-vs-3-7-flash%2Fsame-rate-task-cost.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/..%2F..%2F..%2Fassets%2Fuploads%2Fgemini-3-8-flash-vs-3-7-flash%2Fsame-rate-task-cost.webp" alt="Gemini 3.8 Flash and 3.7 Flash task-cost comparison across tokens, reasoning steps, tool calls and completion cost" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What actually improved for coding and agents?
&lt;/h2&gt;

&lt;p&gt;Google positions Gemini 3.8 Flash around &lt;strong&gt;long-horizon software engineering&lt;/strong&gt; and &lt;strong&gt;autonomous agents&lt;/strong&gt;, not generic chat quality.&lt;/p&gt;

&lt;p&gt;The launch material points to four practical areas:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Long-running software engineering:&lt;/strong&gt; multi-file and multi-stage tasks that require continued verification;&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Agentic workflows:&lt;/strong&gt; multi-step planning and tool orchestration with fewer failed loops;&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Complex professional workflows:&lt;/strong&gt; analytical and reporting tasks that need multiple checks;&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Iterative tool verification:&lt;/strong&gt; more willingness to use tool feedback to refine a result instead of stopping after one generation.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Google’s published DeepSWE and Vals Finance Agent results support that direction, but they remain vendor evaluations. Whether 3.8 is better in your repository still depends on tool definitions, codebase size, run length, recovery design and budget constraints.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/..%2F..%2F..%2Fassets%2Fuploads%2Fgemini-3-8-flash-vs-3-7-flash%2Fcoding-agent-workflow.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/..%2F..%2F..%2Fassets%2Fuploads%2Fgemini-3-8-flash-vs-3-7-flash%2Fcoding-agent-workflow.webp" alt="Gemini 3.8 Flash and 3.7 Flash in an agent workflow from user request through reasoning, tool use, code edits and verified output" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  How do you call Gemini 3.8 Flash in the API?
&lt;/h2&gt;

&lt;p&gt;The model ID is straightforward:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;gemini-3.8-flash
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Google currently labels the model GA and provides examples through the Gemini Interactions API.&lt;/p&gt;

&lt;p&gt;The migration work is more important than the model string. Google’s 3.8 migration checklist calls out several configuration changes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;remove deprecated &lt;code&gt;temperature&lt;/code&gt;, &lt;code&gt;top_p&lt;/code&gt; and &lt;code&gt;top_k&lt;/code&gt; generation parameters;&lt;/li&gt;
&lt;li&gt;replace &lt;code&gt;thinking_budget&lt;/code&gt; with the string &lt;code&gt;thinking_level&lt;/code&gt; enum;&lt;/li&gt;
&lt;li&gt;do not use &lt;code&gt;minimal&lt;/code&gt; with 3.8 Flash;&lt;/li&gt;
&lt;li&gt;remove unsupported &lt;code&gt;candidate_count&lt;/code&gt;;&lt;/li&gt;
&lt;li&gt;standardize multi-turn conversations on server-side &lt;code&gt;previous_interaction_id&lt;/code&gt;;&lt;/li&gt;
&lt;li&gt;audit function-calling payloads, including &lt;code&gt;call_id&lt;/code&gt; and &lt;code&gt;name&lt;/code&gt; where required;&lt;/li&gt;
&lt;li&gt;do not assume older Gemini 2.x or early 3.x sampling/prompt behavior will migrate unchanged.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If a project only replaces &lt;code&gt;gemini-3.7-flash&lt;/code&gt; with &lt;code&gt;gemini-3.8-flash&lt;/code&gt; and ignores those constraints, a migration error can easily be mistaken for a model-quality regression.&lt;/p&gt;

&lt;h2&gt;
  
  
  Which thinking level should you use?
&lt;/h2&gt;

&lt;p&gt;Google’s current guidance maps cleanly to a production routing strategy:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Workload&lt;/th&gt;
&lt;th&gt;Reasonable starting point&lt;/th&gt;
&lt;th&gt;Why&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Real-time chat, short summaries, light data work&lt;/td&gt;
&lt;td&gt;low&lt;/td&gt;
&lt;td&gt;Prioritize latency and token efficiency&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Code analysis, general agents, multi-step business flows&lt;/td&gt;
&lt;td&gt;medium&lt;/td&gt;
&lt;td&gt;Default balance of quality and cost&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Hard reasoning, difficult coding, complex multi-tool workflows&lt;/td&gt;
&lt;td&gt;high&lt;/td&gt;
&lt;td&gt;Maximize reasoning and tool orchestration&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Do not treat &lt;code&gt;high&lt;/code&gt; as a universal production default. One common way to waste agent budget is to run every task at maximum reasoning intensity.&lt;/p&gt;

&lt;p&gt;A better policy is task routing: simple jobs on low, complex jobs on medium, and only truly hard paths on high.&lt;/p&gt;

&lt;h2&gt;
  
  
  Should existing Gemini 3.7 Flash workloads upgrade now?
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Stronger candidates for immediate 3.8 evaluation
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;coding agents that routinely edit multiple files;&lt;/li&gt;
&lt;li&gt;workflows that run across many steps and repeatedly execute tests or builds;&lt;/li&gt;
&lt;li&gt;agents that call multiple tools and plan from their results;&lt;/li&gt;
&lt;li&gt;workloads where 3.7’s main problem is failed loops or human takeover rather than single-call latency;&lt;/li&gt;
&lt;li&gt;systems that already record token use, success rate, retries and correction time per task.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Reasons to stay on 3.7 for now
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;the workload is stable and cost/latency are already predictable;&lt;/li&gt;
&lt;li&gt;tasks are short and tool use is light;&lt;/li&gt;
&lt;li&gt;you do not yet have a repeatable regression suite to measure migration impact;&lt;/li&gt;
&lt;li&gt;per-task token budget matters more than hard-task completion rate.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Google explicitly says 3.7 Flash remains fully supported, so there is no official “3.8 shipped, therefore migrate now” requirement.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/..%2F..%2F..%2Fassets%2Fuploads%2Fgemini-3-8-flash-vs-3-7-flash%2Fupgrade-decision.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/..%2F..%2F..%2Fassets%2Fuploads%2Fgemini-3-8-flash-vs-3-7-flash%2Fupgrade-decision.webp" alt="Gemini 3.8 Flash versus 3.7 Flash upgrade decision for complex agents, long coding tasks and stable efficiency-first workloads" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Is Gemini 3.8 Flash Cyber just a stronger 3.8 Flash?
&lt;/h2&gt;

&lt;p&gt;Not for normal API selection.&lt;/p&gt;

&lt;p&gt;Gemini 3.8 Flash Cyber is intended for high-permission defensive cybersecurity work and is distributed through the Fairwind Program to trusted governments, critical-infrastructure operators, software maintainers and other approved defenders. It has a different safety/access boundary and should not be treated as the normal “Pro” tier of Gemini 3.8 Flash.&lt;/p&gt;

&lt;p&gt;For ordinary coding agents and enterprise workflows, the useful comparison is &lt;strong&gt;3.8 Flash vs 3.7 Flash&lt;/strong&gt;, not “can I get Cyber?”&lt;/p&gt;

&lt;h2&gt;
  
  
  Gemini 3.8 Flash vs 3.7 Flash: which one should you choose?
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Situation&lt;/th&gt;
&lt;th&gt;More reasonable choice&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;New complex coding agent&lt;/td&gt;
&lt;td&gt;Evaluate 3.8 Flash first&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Existing agent has multi-step failure loops&lt;/td&gt;
&lt;td&gt;Run a controlled 3.8-vs-3.7 regression suite&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Cost-sensitive short tasks&lt;/td&gt;
&lt;td&gt;Keep 3.7 or test 3.8 at low effort&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;“Same price means automatic upgrade”&lt;/td&gt;
&lt;td&gt;Compare per-task tokens and completion cost first&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Need high-permission cyber defense&lt;/td&gt;
&lt;td&gt;Review 3.8 Flash Cyber/Fairwind eligibility separately&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;No regression suite exists&lt;/td&gt;
&lt;td&gt;Build the task set before migrating&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;If you are also comparing the newest Claude coding/agent releases, see &lt;a href="https://www.xbstack.com/en/ai/claude-fable-5-1-vs-mythos-5-1/?utm_source=devto&amp;amp;utm_medium=referral&amp;amp;utm_campaign=article_distribution&amp;amp;utm_content=gemini-3-8-flash-vs-3-7-flash&amp;amp;ref=devto" rel="noopener noreferrer"&gt;Claude Fable 5.1 vs Mythos 5.1: pricing, access, coding and agent trade-offs&lt;/a&gt;. Read together, the releases point to the same broader trend: model competition is moving from single-turn chat scores toward long-running coding, agent tool use and total cost to complete a real task.&lt;/p&gt;

&lt;p&gt;To turn that model choice into production routing, cost controls, approvals and regression evaluation, continue with &lt;a href="https://www.xbstack.com/en/ai/ai-agent-production-governance/?utm_source=devto&amp;amp;utm_medium=referral&amp;amp;utm_campaign=article_distribution&amp;amp;utm_content=gemini-3-8-flash-vs-3-7-flash&amp;amp;ref=devto" rel="noopener noreferrer"&gt;Production Governance for AI Agents&lt;/a&gt;. For repository, issue, log and engineering workflows, use &lt;a href="https://www.xbstack.com/en/ai/ai-developer-operations-agents/?utm_source=devto&amp;amp;utm_medium=referral&amp;amp;utm_campaign=article_distribution&amp;amp;utm_content=gemini-3-8-flash-vs-3-7-flash&amp;amp;ref=devto" rel="noopener noreferrer"&gt;AI Developer Engineering Agents&lt;/a&gt; as the next implementation layer.&lt;/p&gt;

&lt;h2&gt;
  
  
  What would a real XBSTACK benchmark need to test?
&lt;/h2&gt;

&lt;p&gt;A useful test should not repeat a vendor leaderboard. It should lock a set of real tasks:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;the same multi-file code change;&lt;/li&gt;
&lt;li&gt;the same tool-calling agent workflow;&lt;/li&gt;
&lt;li&gt;the same long-document or data-analysis job;&lt;/li&gt;
&lt;li&gt;identical thinking levels and tool permissions;&lt;/li&gt;
&lt;li&gt;success rate, manual edits, input/output tokens, tool-call count and final cost;&lt;/li&gt;
&lt;li&gt;at least one preserved failure case instead of only best-case outputs.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Only after that matrix is repeatable should “3.8 is more reliable” or “3.8 is cheaper per completed task” become an XBSTACK hands-on conclusion.&lt;/p&gt;

&lt;h2&gt;
  
  
  FAQ
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Is Gemini 3.8 Flash available through the API now?
&lt;/h3&gt;

&lt;p&gt;Yes. Google’s developer guide lists &lt;code&gt;gemini-3.8-flash&lt;/code&gt; as GA and provides Interactions API examples.&lt;/p&gt;

&lt;h3&gt;
  
  
  Is Gemini 3.8 Flash more expensive than 3.7 Flash?
&lt;/h3&gt;

&lt;p&gt;Not on the current per-token rate card. Both are $0.75/M input and $3.75/M output through December 31, 2026. But 3.8 can use more reasoning/tool-call tokens on difficult tasks, so the total bill for one completed task can differ.&lt;/p&gt;

&lt;h3&gt;
  
  
  What is the Gemini 3.8 Flash context window?
&lt;/h3&gt;

&lt;p&gt;Google currently lists a 1M-token context window and a 64K-token maximum output.&lt;/p&gt;

&lt;h3&gt;
  
  
  Does Gemini 3.8 Flash support minimal thinking?
&lt;/h3&gt;

&lt;p&gt;No. The current supported levels are &lt;code&gt;low&lt;/code&gt;, &lt;code&gt;medium&lt;/code&gt; and &lt;code&gt;high&lt;/code&gt;. Google says &lt;code&gt;minimal&lt;/code&gt; will return an error.&lt;/p&gt;

&lt;h3&gt;
  
  
  Is Gemini 3.7 Flash being discontinued?
&lt;/h3&gt;

&lt;p&gt;Google explicitly says 3.7 Flash remains fully supported and presents it as an option for efficiency-first workloads.&lt;/p&gt;

&lt;h3&gt;
  
  
  Should I switch production traffic directly to 3.8?
&lt;/h3&gt;

&lt;p&gt;Not based on the version number alone. Run your real regression tasks first and compare success rate, token use, tool calls, corrections and latency before changing the default route.&lt;/p&gt;

&lt;h2&gt;
  
  
  Official sources
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://blog.google/innovation-and-ai/models-and-research/gemini-models/3-8-flash-and-3-8-flash-cyber/" rel="noopener noreferrer"&gt;Google — Introducing Gemini 3.8 Flash and 3.8 Flash Cyber&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://ai.google.dev/gemini-api/docs/latest-model" rel="noopener noreferrer"&gt;Gemini API — What’s new in Gemini 3.8 Flash&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://ai.google.dev/gemini-api/docs/pricing" rel="noopener noreferrer"&gt;Gemini Developer API pricing&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://deepmind.google/models/model-cards/gemini-3-8-flash/" rel="noopener noreferrer"&gt;Google DeepMind — Gemini 3.8 Flash Model Card&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://deepmind.google/models/model-cards/gemini-3-7-flash/" rel="noopener noreferrer"&gt;Google DeepMind — Gemini 3.7 Flash Model Card&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;Canonical article on XBSTACK：&lt;a href="https://www.xbstack.com/en/ai/gemini-3-8-flash-vs-3-7-flash/?utm_source=devto&amp;amp;utm_medium=referral&amp;amp;utm_campaign=article_distribution&amp;amp;utm_content=gemini-3-8-flash-vs-3-7-flash&amp;amp;ref=devto" rel="noopener noreferrer"&gt;https://www.xbstack.com/en/ai/gemini-3-8-flash-vs-3-7-flash/?utm_source=devto&amp;amp;utm_medium=referral&amp;amp;utm_campaign=article_distribution&amp;amp;utm_content=gemini-3-8-flash-vs-3-7-flash&amp;amp;ref=devto&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;标签：#AI #SoftwareEngineering #DeveloperTools #Gemini #Google AI&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Claude Fable 5.1 vs Mythos 5.1: Same Model, Different Access Boundary</title>
      <dc:creator>xn</dc:creator>
      <pubDate>Wed, 02 Sep 2026 07:51:50 +0000</pubDate>
      <link>https://dev.to/xbstack/claude-fable-51-vs-mythos-51-same-model-different-access-boundary-1n55</link>
      <guid>https://dev.to/xbstack/claude-fable-51-vs-mythos-51-same-model-different-access-boundary-1n55</guid>
      <description>&lt;p&gt;Claude Fable 5.1 and Claude Mythos 5.1 look like a normal model split at first glance. They are not.&lt;/p&gt;

&lt;p&gt;The important line in Anthropic’s launch post is that both names refer to the same underlying model. The difference is the safeguard configuration and who is allowed to use each access path.&lt;/p&gt;

&lt;h2&gt;
  
  
  The practical decision
&lt;/h2&gt;

&lt;p&gt;For most developers, the decision is simple: evaluate Claude Fable 5.1 first. Fable is the generally available version across Claude products, the API, Claude Code, and major cloud platforms.&lt;/p&gt;

&lt;p&gt;Mythos is not a higher tier that a regular developer unlocks by paying more. It is restricted to vetted cybersecurity and life-sciences organizations through trusted access programs.&lt;/p&gt;

&lt;h2&gt;
  
  
  Pricing is only part of the story
&lt;/h2&gt;

&lt;p&gt;The standard Fable 5.1 API price remains $10 per million input tokens and $50 per million output tokens. The more interesting change is cache read pricing: $0.25 per million tokens.&lt;/p&gt;

&lt;p&gt;That matters for agent workloads because agents often carry the same repository context, tool descriptions, project policies, and task state through multiple steps. If the workflow can reuse cached context, the effective cost profile changes.&lt;/p&gt;

&lt;h2&gt;
  
  
  Do not over-read vendor benchmarks
&lt;/h2&gt;

&lt;p&gt;Terminal-Bench and CursorBench are useful signals, but they are not a substitute for running the model against your own repository, prompts, tools, and acceptance criteria. A coding-agent workflow can fail because of tool permissions, state recovery, cache misses, or data-retention constraints even when the base model is strong.&lt;/p&gt;

&lt;p&gt;My working rule is: treat Fable 5.1 as a candidate for the normal production evaluation matrix; treat Mythos 5.1 as a specialized access program, not a default upgrade path.&lt;/p&gt;

&lt;p&gt;Canonical article and full comparison: &lt;a href="https://www.xbstack.com/en/ai/claude-fable-5-1-vs-mythos-5-1/?utm_source=devto&amp;amp;utm_medium=referral&amp;amp;utm_campaign=claude_fable_mythos_51&amp;amp;utm_content=original&amp;amp;ref=devto" rel="noopener noreferrer"&gt;https://www.xbstack.com/en/ai/claude-fable-5-1-vs-mythos-5-1/?utm_source=devto&amp;amp;utm_medium=referral&amp;amp;utm_campaign=claude_fable_mythos_51&amp;amp;utm_content=original&amp;amp;ref=devto&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Related reading
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.xbstack.com/en/ai/ai-agent-framework-comparison/?utm_source=devto&amp;amp;utm_medium=referral&amp;amp;utm_campaign=claude_fable_mythos_51&amp;amp;utm_content=related_1&amp;amp;ref=devto" rel="noopener noreferrer"&gt;AI Agent framework comparison&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.xbstack.com/en/ai/ai-agent-tool-authorization-policy-gate/?utm_source=devto&amp;amp;utm_medium=referral&amp;amp;utm_campaign=claude_fable_mythos_51&amp;amp;utm_content=related_2&amp;amp;ref=devto" rel="noopener noreferrer"&gt;Agent tool authorization gates&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.xbstack.com/en/ai/openai-zero-data-retention-agent-data-boundary/?utm_source=devto&amp;amp;utm_medium=referral&amp;amp;utm_campaign=claude_fable_mythos_51&amp;amp;utm_content=related_3&amp;amp;ref=devto" rel="noopener noreferrer"&gt;OpenAI Zero Data Retention boundaries&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
    </item>
    <item>
      <title>MCP StreamableHTTPClientTransport POST Stays Pending After SSE Disconnect: Issue #2739 Re…</title>
      <dc:creator>xn</dc:creator>
      <pubDate>Tue, 01 Sep 2026 03:31:52 +0000</pubDate>
      <link>https://dev.to/xbstack/mcp-streamablehttpclienttransport-post-stays-pending-after-sse-disconnect-issue-2739-re-59hp</link>
      <guid>https://dev.to/xbstack/mcp-streamablehttpclienttransport-post-stays-pending-after-sse-disconnect-issue-2739-re-59hp</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;A production-focused update based on a real project: A v1 MCP StreamableHTTPClientTransport POST can remain pending until request timeout after request-scoped SSE error/EOF. XBSTA…&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;If you use the v1 &lt;code&gt;@modelcontextprotocol/sdk&lt;/code&gt; &lt;code&gt;StreamableHTTPClientTransport&lt;/code&gt; and see a strange failure pattern—&lt;strong&gt;the POST has already received &lt;code&gt;text/event-stream&lt;/code&gt;, the request-scoped SSE has died, &lt;code&gt;client.onerror&lt;/code&gt; may already have fired, but &lt;code&gt;client.ping()&lt;/code&gt; or another request still sits pending until the normal request timeout&lt;/strong&gt;—do not automatically classify it as a slow server or a generic network timeout.&lt;/p&gt;

&lt;p&gt;On September 1, 2026, I independently reran the lifecycle boundary described in upstream &lt;a href="https://github.com/modelcontextprotocol/typescript-sdk/issues/2739" rel="noopener noreferrer"&gt;Issue #2739&lt;/a&gt; on Node.js 22.18.0. &lt;code&gt;@modelcontextprotocol/sdk&lt;/code&gt; 1.29.0 and the current npm release, 1.30.0, both reproduce it. In the erroring-SSE case, the transport reports the failure within roughly 3–4 ms, yet the JSON-RPC request rejects only when the 300 ms test timeout expires. With clean EOF, there is no &lt;code&gt;client.onerror&lt;/code&gt; in the reproduction and the request still waits for timeout. An &lt;code&gt;application/json&lt;/code&gt; control resolves in about 1 ms.&lt;/p&gt;

&lt;p&gt;This article stays narrow: &lt;strong&gt;why a request-scoped SSE leg can become incapable of delivering its JSON-RPC result while the corresponding v1 request remains pending, and what you can safely do until the SDK lifecycle is fixed.&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  First, verify that your failure matches this boundary
&lt;/h2&gt;

&lt;p&gt;The closer your case is to these conditions, the more relevant #2739 becomes:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;You are on the v1 &lt;code&gt;@modelcontextprotocol/sdk&lt;/code&gt; &lt;code&gt;StreamableHTTPClientTransport&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;The POST response uses &lt;code&gt;Content-Type: text/event-stream&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;The server accepted the JSON-RPC request.&lt;/li&gt;
&lt;li&gt;The request-scoped SSE body errors or reaches EOF before the matching JSON-RPC &lt;code&gt;result&lt;/code&gt; or &lt;code&gt;error&lt;/code&gt; arrives.&lt;/li&gt;
&lt;li&gt;In the error case, &lt;code&gt;client.onerror&lt;/code&gt; may fire quickly while the request Promise remains unsettled.&lt;/li&gt;
&lt;li&gt;The final caller-visible failure is just &lt;code&gt;MCP error -32001: Request timed out&lt;/code&gt;.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This is not the same diagnostic path as initialization failure, HTTP 401/403, &lt;code&gt;-32700 Parse error&lt;/code&gt;, reverse-proxy buffering, a server that never accepted the POST, or a stream lost only after explicit cancellation. Upstream #2739 explicitly distinguishes its no-cancellation reproduction from related lifecycle issue &lt;a href="https://github.com/modelcontextprotocol/typescript-sdk/issues/2691" rel="noopener noreferrer"&gt;#2691&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Reproduction design: three POST response modes, no real server required
&lt;/h2&gt;

&lt;p&gt;I wanted to remove OAuth, reverse proxies, external networking, model APIs and tool logic from the experiment. Instead of running a real remote MCP server, the test injects a custom &lt;code&gt;fetch&lt;/code&gt; into &lt;code&gt;StreamableHTTPClientTransport&lt;/code&gt;. Initialization returns normal JSON; only the &lt;code&gt;ping&lt;/code&gt; response changes:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;A. erroring SSE
POST ping -&amp;gt; text/event-stream -&amp;gt; controller.error()

B. clean EOF
POST ping -&amp;gt; text/event-stream -&amp;gt; controller.close()

C. JSON control
POST ping -&amp;gt; application/json -&amp;gt; matching JSON-RPC result
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The request timeout is fixed at 300 ms. That isolates one question: &lt;strong&gt;if the transport knows within a few milliseconds that the request-scoped SSE leg can no longer deliver a result, does the request Promise settle immediately?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The key test fragment is small:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;method&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;ping&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;body&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;ReadableStream&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="nf"&gt;start&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;controller&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nf"&gt;queueMicrotask&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;controller&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;response leg lost&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)));&lt;/span&gt;
      &lt;span class="c1"&gt;// Replace with controller.close() for the clean-EOF case.&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Response&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;content-type&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;text/event-stream&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The harness timestamps both &lt;code&gt;client.onerror&lt;/code&gt; and the eventual settlement of &lt;code&gt;client.ping({ timeout: 300 })&lt;/code&gt;. The full local asset lives in &lt;code&gt;experiments/mcp-streamable-http-sse-pending-repro/&lt;/code&gt;, including raw logs and a version matrix.&lt;/p&gt;

&lt;h2&gt;
  
  
  SDK 1.29.0: transport error at 4 ms, request failure at 304 ms
&lt;/h2&gt;

&lt;p&gt;The first local run used &lt;code&gt;@modelcontextprotocol/sdk&lt;/code&gt; 1.29.0 on Node.js 22.18.0:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;error:
  onerror = 4ms
  request rejected = 304ms
  final error = MCP error -32001: Request timed out

eof:
  onerror = none
  request rejected = 302ms
  final error = MCP error -32001: Request timed out

json-control:
  request resolved = 1ms
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The interesting number is not 304 ms by itself. Production timeouts may be seconds or much longer. The important observation is the separation between two clocks: &lt;strong&gt;the transport already knows at about 4 ms that the SSE stream failed, but the JSON-RPC request does not reject at about 4 ms.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Clean EOF is even harder to observe. A stream ending cleanly is not proof that the matching JSON-RPC response arrived. In this minimal case, there is no &lt;code&gt;onerror&lt;/code&gt;, no result and no request settlement until the timeout.&lt;/p&gt;

&lt;h2&gt;
  
  
  The current 1.30.0 release still reproduces the same lifecycle gap
&lt;/h2&gt;

&lt;p&gt;Upstream Issue #2739 was opened on August 30, 2026 and reports Node 24.18.0 with SDK 1.26.0 and 1.29.0. Before treating that as yesterday's already-fixed bug, I checked npm and found &lt;code&gt;@modelcontextprotocol/sdk&lt;/code&gt; 1.30.0 is the current release. I then reran the exact same local harness without changing the test logic.&lt;/p&gt;

&lt;p&gt;The result remained consistent:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Scenario&lt;/th&gt;
&lt;th&gt;1.29.0&lt;/th&gt;
&lt;th&gt;1.30.0&lt;/th&gt;
&lt;th&gt;What it shows&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Erroring SSE fires &lt;code&gt;onerror&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;~4 ms&lt;/td&gt;
&lt;td&gt;~3 ms&lt;/td&gt;
&lt;td&gt;Transport sees the stream failure quickly&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Erroring SSE request rejects&lt;/td&gt;
&lt;td&gt;~304 ms&lt;/td&gt;
&lt;td&gt;~306 ms&lt;/td&gt;
&lt;td&gt;Request still waits for timeout&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Clean EOF request rejects&lt;/td&gt;
&lt;td&gt;~302 ms&lt;/td&gt;
&lt;td&gt;~302 ms&lt;/td&gt;
&lt;td&gt;Still waits for timeout, with no &lt;code&gt;onerror&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;JSON control resolves&lt;/td&gt;
&lt;td&gt;~1 ms&lt;/td&gt;
&lt;td&gt;~1 ms&lt;/td&gt;
&lt;td&gt;Normal request settles immediately&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;So the claim I can support as of September 1 is specific: &lt;strong&gt;the v1 lifecycle gap reproduces locally on 1.29.0 and 1.30.0.&lt;/strong&gt; I did not independently rerun 1.26.0; that version is upstream evidence, not XBSTACK test evidence.&lt;/p&gt;

&lt;h2&gt;
  
  
  The root problem is not “the timeout is too long”
&lt;/h2&gt;

&lt;p&gt;The upstream cause analysis fits the local behavior. In the v1 path, &lt;code&gt;send()&lt;/code&gt; starts &lt;code&gt;_handleSseStream()&lt;/code&gt; without exposing the request-scoped stream's complete lifecycle as something Protocol can await. The reader error can reach the global &lt;code&gt;onerror&lt;/code&gt; callback without directly settling the JSON-RPC request that owns this POST response. Clean EOF does not necessarily produce the same transport error signal.&lt;/p&gt;

&lt;p&gt;The resulting state looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;JSON-RPC request pending
        |
        +-- transport.send() already returned
        |
        +-- request-scoped SSE errored / reached EOF
        |
        +-- no matching JSON-RPC result/error
        |
        +-- Protocol has only request timeout left to settle the Promise
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That is why better global network logging is not enough. The missing contract is request ownership: &lt;strong&gt;which SSE response leg belongs to which outbound request, and who rejects that pending request when the leg disappears before delivering all required responses?&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Practical containment: distinguish ordinary JSON results from genuine streaming
&lt;/h2&gt;

&lt;p&gt;If you control the server and the request only needs to return a normal JSON-RPC result, not a request-scoped stream, returning &lt;strong&gt;&lt;code&gt;application/json&lt;/code&gt;&lt;/strong&gt; is a reproducible containment for this particular v1 path.&lt;/p&gt;

&lt;p&gt;The local JSON control resolved in about 1 ms on both tested SDK versions. The difference matters because the JSON response path is awaited by &lt;code&gt;send()&lt;/code&gt;, allowing parsing success/failure to become a request outcome directly.&lt;/p&gt;

&lt;p&gt;A minimal server response looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Response&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;jsonrpc&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;2.0&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;result&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{},&lt;/span&gt;
  &lt;span class="p"&gt;}),&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;content-type&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;application/json&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This does &lt;strong&gt;not&lt;/strong&gt; mean “stop using SSE in MCP.” If the response genuinely needs request-scoped streaming, switching it to JSON changes semantics and merely avoids the failing path. It does not repair it.&lt;/p&gt;

&lt;p&gt;The second containment is a &lt;strong&gt;finite request timeout&lt;/strong&gt; appropriate for the tool SLA and upstream network budget. This prevents an unbounded pending Promise. But it is still only a safety net. If the transport knows after 3 ms that the response leg is gone and the application waits another 30 seconds, the bug is still amplifying failure for almost 30 seconds.&lt;/p&gt;

&lt;h2&gt;
  
  
  What a real SDK fix needs to accomplish
&lt;/h2&gt;

&lt;p&gt;I did not fork the SDK locally and present that as an upstream fix. For the #2739 boundary, a complete lifecycle repair needs at least these properties:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;When a POST creates a request-scoped SSE response, the transport knows which JSON-RPC request IDs it owns.&lt;/li&gt;
&lt;li&gt;The lifecycle resolves normally after all matching responses arrive.&lt;/li&gt;
&lt;li&gt;If a non-resumable SSE body errors or reaches EOF first, the corresponding pending request rejects promptly.&lt;/li&gt;
&lt;li&gt;If the caller times out or aborts, reconnect/resume work cannot continue detached from the request that created it.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This is different from closing the entire client whenever any SSE stream fails. A client may have concurrent work. The important property is request-scoped ownership and settlement, not a coarse connection-wide teardown.&lt;/p&gt;

&lt;h2&gt;
  
  
  Do not generalize this v1 result to MCP 2026-07-28 or TypeScript SDK v2
&lt;/h2&gt;

&lt;p&gt;This boundary matters because the ecosystem is currently mid-migration. Issue #2739 uses v1 &lt;code&gt;@modelcontextprotocol/sdk&lt;/code&gt; and negotiates &lt;code&gt;2025-11-25&lt;/code&gt;, which means the older initialize/initialized and session-era flow.&lt;/p&gt;

&lt;p&gt;MCP 2026-07-28 changes the protocol core to stateless request/response, and the TypeScript SDK v2 packages reorganize the modern serving/client paths. The official v2 migration documentation also states that on a 2026-07-28 Streamable HTTP connection, aborting an in-flight request closes that request's SSE response stream as the protocol cancellation signal.&lt;/p&gt;

&lt;p&gt;Therefore the supported conclusion is not “all MCP Streamable HTTP has this bug.” It is:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;As of September 1, 2026, the v1 &lt;code&gt;@modelcontextprotocol/sdk&lt;/code&gt; 2025-era &lt;code&gt;StreamableHTTPClientTransport&lt;/code&gt; still reproduces #2739's pending-until-timeout behavior on current 1.30.0 when a request-scoped SSE response ends/errors before delivering the matching JSON-RPC result. The v2 / 2026-07-28 path needs separate testing.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;If you are already migrating, use the &lt;a href="https://xbstack.com/en/ai/mcp-streamable-http-deployment/?utm_source=devto&amp;amp;utm_medium=referral&amp;amp;utm_campaign=article_distribution&amp;amp;utm_content=en%2Fmcp-streamable-http-sse-pending-timeout&amp;amp;ref=devto" rel="noopener noreferrer"&gt;MCP Streamable HTTP deployment and 2026-07-28 migration guide&lt;/a&gt; rather than designing a new architecture around this v1 workaround. If the failure is a malformed JSON-RPC message rather than a pending request, use the &lt;a href="https://xbstack.com/en/ai/mcp-json-rpc-parse-error/?utm_source=devto&amp;amp;utm_medium=referral&amp;amp;utm_campaign=article_distribution&amp;amp;utm_content=en%2Fmcp-streamable-http-sse-pending-timeout&amp;amp;ref=devto" rel="noopener noreferrer"&gt;MCP -32700 Parse Error guide&lt;/a&gt;. If the request completes but the tool result is cut off, that is a different &lt;a href="https://xbstack.com/en/ai/mcp-tool-call-truncated-fix/?utm_source=devto&amp;amp;utm_medium=referral&amp;amp;utm_campaign=article_distribution&amp;amp;utm_content=en%2Fmcp-streamable-http-sse-pending-timeout&amp;amp;ref=devto" rel="noopener noreferrer"&gt;MCP Tool Call Result Truncated path&lt;/a&gt;. The &lt;a href="https://xbstack.com/en/ai/mcp/?utm_source=devto&amp;amp;utm_medium=referral&amp;amp;utm_campaign=article_distribution&amp;amp;utm_content=en%2Fmcp-streamable-http-sse-pending-timeout&amp;amp;ref=devto" rel="noopener noreferrer"&gt;MCP engineering hub&lt;/a&gt; connects these troubleshooting paths.&lt;/p&gt;

&lt;h2&gt;
  
  
  Production troubleshooting checklist
&lt;/h2&gt;

&lt;p&gt;When a remote MCP tool call looks stuck and eventually reports only a timeout, I would inspect it in this order:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Record HTTP status and Content-Type.&lt;/strong&gt; Is the POST using JSON or &lt;code&gt;text/event-stream&lt;/code&gt;?&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Timestamp transport errors.&lt;/strong&gt; An early &lt;code&gt;onerror&lt;/code&gt; combined with a much later request timeout is a strong lifecycle clue.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Verify that the SSE stream actually delivered the matching JSON-RPC id.&lt;/strong&gt; HTTP 200 alone does not complete the request.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Separate error from clean EOF.&lt;/strong&gt; Clean stream termination may be silent at the transport error hook.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Check for explicit abort, DELETE or timeout first.&lt;/strong&gt; Cancellation paths overlap in symptoms but are not identical to #2739.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;A/B a normal JSON response when the result does not need streaming.&lt;/strong&gt; Immediate JSON settlement versus SSE timeout narrows the fault domain sharply.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Keep a finite request timeout.&lt;/strong&gt; Treat it as a containment boundary, not the root-cause fix.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Final decision
&lt;/h2&gt;

&lt;p&gt;This is more than a cosmetic “increase the timeout” problem. In a production MCP client, the dangerous part is state disagreement: &lt;strong&gt;observability already knows the SSE leg is gone while the application still treats the JSON-RPC request as running.&lt;/strong&gt; At concurrency, those unnecessary pending requests consume task slots, retry budgets and upstream state.&lt;/p&gt;

&lt;p&gt;My current routing decision is:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Maintaining a v1 client: keep explicit request timeouts and use JSON responses for non-streaming request results when you control the server.&lt;/li&gt;
&lt;li&gt;Depending on request-scoped SSE: do not treat the JSON containment as a real fix; track the #2739 lifecycle repair.&lt;/li&gt;
&lt;li&gt;Building or migrating to 2026-07-28: verify the v2/modern path separately instead of inheriting this v1 conclusion.&lt;/li&gt;
&lt;li&gt;Operating production clients: log both the transport-error timestamp and the JSON-RPC request-settlement timestamp; the gap between them is itself valuable diagnostic evidence.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The exact reproduction, version matrix and raw logs are being published as a GitHub asset. If upstream ships a fix, I will use the same three scenarios as a regression test and update this page with the first verified fixed version.&lt;/p&gt;




&lt;p&gt;Canonical article on XBSTACK：&lt;a href="https://www.xbstack.com/en/ai/mcp-streamable-http-sse-pending-timeout/?utm_source=devto&amp;amp;utm_medium=referral&amp;amp;utm_campaign=article_distribution&amp;amp;utm_content=en%2Fmcp-streamable-http-sse-pending-timeout&amp;amp;ref=devto" rel="noopener noreferrer"&gt;https://www.xbstack.com/en/ai/mcp-streamable-http-sse-pending-timeout/?utm_source=devto&amp;amp;utm_medium=referral&amp;amp;utm_campaign=article_distribution&amp;amp;utm_content=en%2Fmcp-streamable-http-sse-pending-timeout&amp;amp;ref=devto&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;标签：#AI #SoftwareEngineering #DeveloperTools #MCP #Streamable HTTP&lt;/p&gt;

</description>
    </item>
    <item>
      <title>How to Security-Check an MCP Configuration: Secrets, Shell, Remote MCP, and Permissions</title>
      <dc:creator>xn</dc:creator>
      <pubDate>Mon, 31 Aug 2026 10:13:18 +0000</pubDate>
      <link>https://dev.to/xbstack/how-to-security-check-an-mcp-configuration-secrets-shell-remote-mcp-and-permissions-4c5j</link>
      <guid>https://dev.to/xbstack/how-to-security-check-an-mcp-configuration-secrets-shell-remote-mcp-and-permissions-4c5j</guid>
      <description>&lt;p&gt;The configuration problems most likely to survive into production are often not JSON syntax errors. They are &lt;strong&gt;credential and permission boundaries that work well enough to be ignored&lt;/strong&gt;: real credentials stored in config, an overly broad shell boundary, a remote MCP endpoint treated as an ordinary URL, authentication data copied into logs, or a read-only agent running with write privileges.&lt;/p&gt;

&lt;p&gt;Static scanning is useful here, but the opposite failure mode is also common: treating every &lt;code&gt;command&lt;/code&gt;, &lt;code&gt;shell&lt;/code&gt; or &lt;code&gt;env&lt;/code&gt; field as a critical vulnerability. Security findings need execution context.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. Exposed credentials
&lt;/h2&gt;

&lt;p&gt;The problem is not the name of an environment variable. The problem is a real secret value ending up in a file that can be committed, copied, logged or screenshotted.&lt;/p&gt;

&lt;p&gt;A safer configuration stores only references or identifiers and injects the real value through a controlled runtime environment. Documentation, issues and screenshots should use redacted placeholders rather than production values.&lt;/p&gt;

&lt;p&gt;MCP authorization guidance distinguishes HTTP and stdio transports. A local stdio process should not copy an HTTP OAuth flow; credentials should come from an appropriate local secure environment. Remote HTTP servers need explicit authorization boundaries such as protected-resource metadata, resource binding and appropriately scoped credentials rather than one long-lived credential copied into every client.&lt;/p&gt;

&lt;p&gt;Before deployment, review whether the config is version-controlled, whether errors echo authentication fields, whether CI can copy credentials into public artifacts, and whether example config is likely to be pasted into a public repository.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. Shell is not automatically a vulnerability
&lt;/h2&gt;

&lt;p&gt;These are very different execution boundaries:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;fixed executable + fixed working directory + constrained parameters
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;versus:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;general command interpreter + model-controlled arguments + privileged identity
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When a scanner finds &lt;code&gt;bash&lt;/code&gt;, &lt;code&gt;sh&lt;/code&gt;, &lt;code&gt;powershell&lt;/code&gt; or another command execution surface, the next questions are more important than the keyword itself:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Can user or model input reach command arguments?&lt;/li&gt;
&lt;li&gt;Is the working directory constrained?&lt;/li&gt;
&lt;li&gt;Are arbitrary filesystem, network or child-process actions possible?&lt;/li&gt;
&lt;li&gt;Does the process run with more privilege than the task needs?&lt;/li&gt;
&lt;li&gt;Do mutating operations require authorization or confirmation?&lt;/li&gt;
&lt;li&gt;Are commands and outputs copied into logs?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;String matching can identify a review point. It cannot prove an arbitrary-command-execution vulnerability on its own.&lt;/p&gt;

&lt;h2&gt;
  
  
  3. A remote MCP endpoint is a trust boundary
&lt;/h2&gt;

&lt;p&gt;Connecting to remote MCP is not the same as calling an ordinary content URL. The agent may receive Tools, Resources or Prompts from the server. Before trusting the connection, confirm:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;The domain and documentation belong to the expected provider.&lt;/li&gt;
&lt;li&gt;The endpoint uses HTTPS.&lt;/li&gt;
&lt;li&gt;Authorization material is sent only to the intended resource.&lt;/li&gt;
&lt;li&gt;Scopes are no broader than necessary.&lt;/li&gt;
&lt;li&gt;Remote tool descriptions and returned content are treated as model input with appropriate validation.&lt;/li&gt;
&lt;li&gt;Access can be revoked when the provider or connection changes.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Notion's MCP security guidance similarly tells users to verify official endpoints and reminds them that connecting MCP can expose the connected user's workspace permissions to the AI system using that connection. If the remote endpoint also needs protocol, catalog, and authorization preflight, continue with the &lt;a href="https://www.xbstack.com/en/ai/mcp-server-read-only-preflight-inspector/?utm_source=devto&amp;amp;utm_medium=referral&amp;amp;utm_campaign=mcp_config_security&amp;amp;utm_content=body_link&amp;amp;ref=devto" rel="noopener noreferrer"&gt;read-only MCP Server preflight&lt;/a&gt; so configuration risk and protocol health stay separate.&lt;/p&gt;

&lt;h2&gt;
  
  
  4. Logging and retention are separate controls
&lt;/h2&gt;

&lt;p&gt;A provider-level data control does not imply that your MCP client, agent memory, traces, application database and logs all have the same retention behavior.&lt;/p&gt;

&lt;p&gt;Review these independently:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;authentication headers in logs;&lt;/li&gt;
&lt;li&gt;sensitive fields in tool arguments;&lt;/li&gt;
&lt;li&gt;full request bodies in error logging;&lt;/li&gt;
&lt;li&gt;trace retention;&lt;/li&gt;
&lt;li&gt;local caches, memory and vector-store cleanup.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is the same distinction covered in &lt;a href="https://www.xbstack.com/en/ai/openai-zero-data-retention-agent-data-boundary/?utm_source=devto&amp;amp;utm_medium=referral&amp;amp;utm_campaign=mcp_config_security&amp;amp;utm_content=body_link&amp;amp;ref=devto" rel="noopener noreferrer"&gt;OpenAI ZDR and Agent data boundaries&lt;/a&gt;: provider controls and end-to-end agent retention are not interchangeable claims.&lt;/p&gt;

&lt;h2&gt;
  
  
  Run a browser-local static check
&lt;/h2&gt;

&lt;p&gt;The &lt;a href="https://www.xbstack.com/en/tools/agent-security-auditor/?utm_source=devto&amp;amp;utm_medium=referral&amp;amp;utm_campaign=mcp_config_security&amp;amp;utm_content=body_link&amp;amp;ref=devto" rel="noopener noreferrer"&gt;XBSTACK Agent Security Auditor&lt;/a&gt; is designed as a browser-local static scanner. Paste &lt;strong&gt;redacted&lt;/strong&gt; MCP/Agent configuration or code, and it reviews signals around credentials, shell boundaries, remote MCP, permissions, retention, logging and execution limits.&lt;/p&gt;

&lt;p&gt;A useful workflow is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;1. Redact real credentials before copying anything
2. Run the local scan
3. Use each finding to locate the exact field
4. Decide whether it is a real risk or an intentionally constrained configuration
5. Fix the boundary
6. Scan again and keep before/after evidence
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The evidence-plus-review step matters. A fixed read-only script may legitimately be launched through a shell; the scanner should surface the boundary, but the presence of &lt;code&gt;bash&lt;/code&gt; alone does not prove arbitrary command execution.&lt;/p&gt;

&lt;h2&gt;
  
  
  Pre-deployment checklist
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[ ] No real credentials in repository/config examples
[ ] Remote MCP endpoint matches provider documentation
[ ] HTTP authorization resource and scope match the intended service
[ ] Shell/command parameter sources are controlled
[ ] Filesystem and network permissions are task-scoped
[ ] Mutating operations require business authorization or confirmation
[ ] Logs do not retain secrets
[ ] Trace/Memory/DB retention has an explicit policy
[ ] Third-party MCP/dependency provenance is known
[ ] Test and production credentials are separated
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If several of these are unknown, fix the boundaries before adding more tools.&lt;/p&gt;

&lt;h2&gt;
  
  
  Bottom line
&lt;/h2&gt;

&lt;p&gt;MCP configuration security is not "remove every command" and it is not "OAuth means safe." The real questions are &lt;strong&gt;where credentials live, who can invoke what, under which execution identity, where data is retained, and who supplies remote capabilities&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Agent Security Auditor helps surface those configuration-level signals quickly and consistently. Production security still depends on code review, runtime permissions, server-side authorization, dependency governance and business-level tests.&lt;/p&gt;




&lt;h2&gt;
  
  
  Source and related reading
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.xbstack.com/en/ai/mcp-config-secret-permission-security-audit/?utm_source=devto&amp;amp;utm_medium=referral&amp;amp;utm_campaign=mcp_config_security&amp;amp;utm_content=original&amp;amp;ref=devto" rel="noopener noreferrer"&gt;Canonical article on XBSTACK&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.xbstack.com/en/ai/mcp-security-best-practices/?utm_source=devto&amp;amp;utm_medium=referral&amp;amp;utm_campaign=mcp_config_security&amp;amp;utm_content=related_1&amp;amp;ref=devto" rel="noopener noreferrer"&gt;MCP security best practices&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.xbstack.com/en/ai/ai-agent-tool-authorization-policy-gate/?utm_source=devto&amp;amp;utm_medium=referral&amp;amp;utm_campaign=mcp_config_security&amp;amp;utm_content=related_2&amp;amp;ref=devto" rel="noopener noreferrer"&gt;Agent tool authorization gates&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.xbstack.com/en/ai/openai-zero-data-retention-agent-data-boundary/?utm_source=devto&amp;amp;utm_medium=referral&amp;amp;utm_campaign=mcp_config_security&amp;amp;utm_content=related_3&amp;amp;ref=devto" rel="noopener noreferrer"&gt;Zero Data Retention boundaries&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
    </item>
    <item>
      <title>How to Test an MCP Server Before Production: Read-Only Inspector Preflight</title>
      <dc:creator>xn</dc:creator>
      <pubDate>Mon, 31 Aug 2026 10:12:40 +0000</pubDate>
      <link>https://dev.to/xbstack/how-to-test-an-mcp-server-before-production-read-only-inspector-preflight-5eoh</link>
      <guid>https://dev.to/xbstack/how-to-test-an-mcp-server-before-production-read-only-inspector-preflight-5eoh</guid>
      <description>&lt;p&gt;A common way to test an MCP server is to open an Inspector and immediately invoke a tool. That is not always the right first step for a production endpoint. &lt;strong&gt;The protocol and catalog layer can be verified with read-only requests before any business action is triggered.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;MCP 2026-07-28 moves the core to stateless request/response and adds &lt;code&gt;server/discover&lt;/code&gt;. It can return supported protocol versions, capabilities and server identity. You can then use &lt;code&gt;tools/list&lt;/code&gt;, &lt;code&gt;resources/list&lt;/code&gt; and &lt;code&gt;prompts/list&lt;/code&gt; to check what the server currently exposes. For authenticated services, the HTTP authorization challenge is itself part of the preflight evidence.&lt;/p&gt;

&lt;h2&gt;
  
  
  What to check before production
&lt;/h2&gt;

&lt;p&gt;I split preflight into six layers:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Endpoint&lt;/strong&gt; — reachability, TLS, redirects and expected HTTP status.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Protocol&lt;/strong&gt; — whether the endpoint supports 2026-07-28 or only a legacy lifecycle.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Discovery&lt;/strong&gt; — whether &lt;code&gt;server/discover&lt;/code&gt; returns valid JSON-RPC and useful capability/version information.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Catalogs&lt;/strong&gt; — whether &lt;code&gt;tools/list&lt;/code&gt;, &lt;code&gt;resources/list&lt;/code&gt; and &lt;code&gt;prompts/list&lt;/code&gt; return valid structures.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Authorization&lt;/strong&gt; — whether unauthenticated access produces a correct 401/metadata/challenge instead of an opaque 500.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Operational signals&lt;/strong&gt; — response time, cache hints and error consistency.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Once these pass, real tool calls are much easier to debug because you have already separated protocol failures from business logic failures.&lt;/p&gt;

&lt;h2&gt;
  
  
  Reading server/discover correctly
&lt;/h2&gt;

&lt;p&gt;A modern MCP server implements &lt;code&gt;server/discover&lt;/code&gt;. The response may expose:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;supportedVersions&lt;/code&gt;;&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;capabilities&lt;/code&gt;;&lt;/li&gt;
&lt;li&gt;server identity metadata;&lt;/li&gt;
&lt;li&gt;optional &lt;code&gt;instructions&lt;/code&gt;;&lt;/li&gt;
&lt;li&gt;cache hints such as &lt;code&gt;ttlMs&lt;/code&gt; and &lt;code&gt;cacheScope&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Two details matter.&lt;/p&gt;

&lt;p&gt;First, a client does &lt;strong&gt;not&lt;/strong&gt; have to call &lt;code&gt;server/discover&lt;/code&gt; before every request. The specification allows a client to send another RPC directly and handle &lt;code&gt;UnsupportedProtocolVersionError&lt;/code&gt; if necessary.&lt;/p&gt;

&lt;p&gt;Second, self-reported server information is useful for display and debugging, but it is not an authentication primitive. Real authorization still depends on OAuth, token audience, scopes and application-level checks.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why validate the list methods too
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;server/discover&lt;/code&gt; tells you what the server says it supports. The list methods show what the endpoint currently exposes:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;server/discover
  -&amp;gt;
tools/list
resources/list
prompts/list
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If the capability metadata says Tools are supported but &lt;code&gt;tools/list&lt;/code&gt; returns an invalid structure, you have a catalog implementation issue rather than a network issue. If a deployment unexpectedly returns zero tools, you can detect that before any real business action is attempted.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why XBSTACK's public Inspector is read-only
&lt;/h2&gt;

&lt;p&gt;The official MCP Inspector is a full developer tool with Web, CLI and TUI clients and support for &lt;code&gt;tools/call&lt;/code&gt;. That is appropriate when a developer is debugging a server they control.&lt;/p&gt;

&lt;p&gt;The &lt;a href="https://www.xbstack.com/en/tools/mcp-inspector/?utm_source=devto&amp;amp;utm_medium=referral&amp;amp;utm_campaign=mcp_readonly_preflight&amp;amp;utm_content=body_link&amp;amp;ref=devto" rel="noopener noreferrer"&gt;XBSTACK MCP Inspector&lt;/a&gt; deliberately uses a narrower boundary for &lt;strong&gt;public remote endpoints&lt;/strong&gt;: discovery, compatibility detection and first-page catalog reads, without sending &lt;code&gt;tools/call&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The reason is operational context. A public web checker does not know what side effect an unknown tool may cause or whether the visitor is authorized to trigger it. So the product is closer to an &lt;strong&gt;MCP endpoint preflight&lt;/strong&gt; than a complete interactive client.&lt;/p&gt;

&lt;h2&gt;
  
  
  The same probe now covers 15 public endpoints
&lt;/h2&gt;

&lt;p&gt;The current &lt;a href="https://www.xbstack.com/en/tools/mcp-radar/?utm_source=devto&amp;amp;utm_medium=referral&amp;amp;utm_campaign=mcp_readonly_preflight&amp;amp;utm_content=body_link&amp;amp;ref=devto" rel="noopener noreferrer"&gt;MCP Protocol Radar&lt;/a&gt; applies the same read-only method to 15 public remote endpoints, including Context7, Microsoft Learn, DeepWiki, GitHub, Vercel, Atlassian Rovo and multiple Cloudflare MCP servers.&lt;/p&gt;

&lt;p&gt;For each endpoint it records the same kinds of observations:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;reachability;&lt;/li&gt;
&lt;li&gt;modern / legacy / unknown classification;&lt;/li&gt;
&lt;li&gt;protocol version;&lt;/li&gt;
&lt;li&gt;tools/resources/prompts counts;&lt;/li&gt;
&lt;li&gt;authorization challenge;&lt;/li&gt;
&lt;li&gt;verification timestamp.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is useful as a compatibility dataset. It should not be presented as a security ranking or official certification.&lt;/p&gt;

&lt;h2&gt;
  
  
  A practical rollout order
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;1. Read-only preflight in a public or controlled environment
2. Confirm protocol and authorization boundaries
3. Invoke read-only tools with a test account
4. Validate authorization/confirmation for write tools
5. Test failure, timeout, retry and duplicate-call behavior
6. Send production traffic
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If step one already shows JSON-RPC parse errors, an empty catalog, a version mismatch or broken OAuth metadata, fix the foundation first. A successful business tool call should not be used to hide protocol-level defects.&lt;/p&gt;

&lt;h2&gt;
  
  
  What a read-only PASS means
&lt;/h2&gt;

&lt;p&gt;It means the endpoint passed the checks that were actually executed at that timestamp.&lt;/p&gt;

&lt;p&gt;It does &lt;strong&gt;not&lt;/strong&gt; mean:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;every tool works;&lt;/li&gt;
&lt;li&gt;permissions are least-privilege;&lt;/li&gt;
&lt;li&gt;tool output is free of prompt-injection risk;&lt;/li&gt;
&lt;li&gt;the server has no application vulnerabilities;&lt;/li&gt;
&lt;li&gt;a future deployment will behave the same way;&lt;/li&gt;
&lt;li&gt;XBSTACK or the MCP project has certified the server.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That is why the radar keeps &lt;code&gt;verifiedAt&lt;/code&gt;, stale state and methodology visible instead of assigning permanent safety labels.&lt;/p&gt;

&lt;p&gt;If you only need to know whether a remote endpoint is healthy enough for deeper debugging, start with the &lt;a href="https://www.xbstack.com/en/tools/mcp-inspector/?utm_source=devto&amp;amp;utm_medium=referral&amp;amp;utm_campaign=mcp_readonly_preflight&amp;amp;utm_content=body_link&amp;amp;ref=devto" rel="noopener noreferrer"&gt;MCP Inspector&lt;/a&gt;. If you want to compare protocol adoption across public servers, use the &lt;a href="https://www.xbstack.com/en/tools/mcp-radar/?utm_source=devto&amp;amp;utm_medium=referral&amp;amp;utm_campaign=mcp_readonly_preflight&amp;amp;utm_content=body_link&amp;amp;ref=devto" rel="noopener noreferrer"&gt;MCP Protocol Radar&lt;/a&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  Source and related reading
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.xbstack.com/en/ai/mcp-server-read-only-preflight-inspector/?utm_source=devto&amp;amp;utm_medium=referral&amp;amp;utm_campaign=mcp_readonly_preflight&amp;amp;utm_content=original&amp;amp;ref=devto" rel="noopener noreferrer"&gt;Canonical article on XBSTACK&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.xbstack.com/en/ai/mcp-2026-07-28-stateless-migration/?utm_source=devto&amp;amp;utm_medium=referral&amp;amp;utm_campaign=mcp_readonly_preflight&amp;amp;utm_content=related_1&amp;amp;ref=devto" rel="noopener noreferrer"&gt;MCP 2026-07-28 migration&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.xbstack.com/en/ai/mcp-json-rpc-parse-error/?utm_source=devto&amp;amp;utm_medium=referral&amp;amp;utm_campaign=mcp_readonly_preflight&amp;amp;utm_content=related_2&amp;amp;ref=devto" rel="noopener noreferrer"&gt;MCP -32700 parse error&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.xbstack.com/en/ai/mcp-security-best-practices/?utm_source=devto&amp;amp;utm_medium=referral&amp;amp;utm_campaign=mcp_readonly_preflight&amp;amp;utm_content=related_3&amp;amp;ref=devto" rel="noopener noreferrer"&gt;MCP security practices&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
    </item>
    <item>
      <title>How to Add WebMCP to a Website: Chrome 149 Forms, Tool Schemas, and registerTool</title>
      <dc:creator>xn</dc:creator>
      <pubDate>Mon, 31 Aug 2026 10:08:57 +0000</pubDate>
      <link>https://dev.to/xbstack/how-to-add-webmcp-to-a-website-chrome-149-forms-tool-schemas-and-registertool-39f2</link>
      <guid>https://dev.to/xbstack/how-to-add-webmcp-to-a-website-chrome-149-forms-tool-schemas-and-registertool-39f2</guid>
      <description>&lt;p&gt;If an older tutorial tells you to use &lt;code&gt;navigator.webmcp&lt;/code&gt;, dump the entire page state into an agent, or treat WebMCP as a magical "AI clicks the website" layer, do not copy it blindly. In the current 2026 documentation, the model is clearer: &lt;strong&gt;the site explicitly registers structured tools, and an agent understands them through stable names, descriptions and input schemas.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Chrome 149 provides a WebMCP origin trial. On August 26, Chrome also published a new design guide that starts from user goals, state transitions and conversational paths instead of telling developers to convert every button into a tool.&lt;/p&gt;

&lt;h2&gt;
  
  
  The simplest path: expose an existing form
&lt;/h2&gt;

&lt;p&gt;If the task is already a form submission—search, filtering, booking, lookup or another explicit request—the declarative API is a good starting point:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;form&lt;/span&gt;
  &lt;span class="na"&gt;toolname=&lt;/span&gt;&lt;span class="s"&gt;"search_docs"&lt;/span&gt;
  &lt;span class="na"&gt;tooldescription=&lt;/span&gt;&lt;span class="s"&gt;"Search XBSTACK technical documentation"&lt;/span&gt;
  &lt;span class="na"&gt;action=&lt;/span&gt;&lt;span class="s"&gt;"/search"&lt;/span&gt;
&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;input&lt;/span&gt;
    &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"q"&lt;/span&gt;
    &lt;span class="na"&gt;toolparamdescription=&lt;/span&gt;&lt;span class="s"&gt;"Technical topic or error message"&lt;/span&gt;
  &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;button&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"submit"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Search&lt;span class="nt"&gt;&amp;lt;/button&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/form&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The page still works like a normal form for people, while an agent gets a task name and parameter meaning. This is most useful when the user-visible UI already represents a coherent task.&lt;/p&gt;

&lt;h2&gt;
  
  
  Richer actions: document.modelContext.registerTool
&lt;/h2&gt;

&lt;p&gt;For tasks that depend on client state, custom validation or non-trivial execution, the current imperative API uses &lt;code&gt;document.modelContext.registerTool&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;modelContext&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;registerTool&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;inspect_agent_readiness&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Inspect the current site for agent-readiness signals.&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;inputSchema&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;object&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;properties&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;url&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;string&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;format&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;uri&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="na"&gt;required&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;url&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="na"&gt;annotations&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;readOnlyHint&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="na"&gt;execute&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;url&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;inspectReadiness&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The important part is the contract, not the syntax. The name should be stable and action-oriented. The description should explain when the tool is useful. The schema should constrain what the agent can submit. A mutating action must not be mislabeled as read-only.&lt;/p&gt;

&lt;h2&gt;
  
  
  Do not register every button
&lt;/h2&gt;

&lt;p&gt;Chrome's August 26 guidance is useful here: start with a user goal, document the starting state and completion state, then identify meaningful state transitions.&lt;/p&gt;

&lt;p&gt;On a commerce page, opening a details panel or switching tabs may be UI mechanics. Checking inventory, adding an item to a cart and placing an order are actual user tasks. Turning every DOM interaction into a tool creates a noisy tool catalog and makes selection harder.&lt;/p&gt;

&lt;p&gt;A good WebMCP tool should map to a &lt;strong&gt;user task&lt;/strong&gt;, not a CSS selector.&lt;/p&gt;

&lt;h2&gt;
  
  
  Security still belongs to your application
&lt;/h2&gt;

&lt;p&gt;WebMCP exposes only the tools you register, but that does not replace authorization. Current Chrome security guidance recommends annotating genuinely read-only tools and constraining cross-origin exposure to trusted origins.&lt;/p&gt;

&lt;p&gt;Deletion, payment, publishing, permission changes and other sensitive operations should still require server-side authorization, parameter validation, confirmations where appropriate, and audit records. The caller being an agent is not a reason to bypass the application's existing security model.&lt;/p&gt;

&lt;h2&gt;
  
  
  How to verify the integration
&lt;/h2&gt;

&lt;p&gt;First, verify functionally in a browser environment that supports the experimental feature: make sure the tool registers, the schema is correct, execution returns the expected result and failure paths are explicit.&lt;/p&gt;

&lt;p&gt;Second, use Lighthouse. Chrome now has a &lt;strong&gt;Registered WebMCP tools&lt;/strong&gt; audit that lists tools registered through the declarative or imperative APIs. An empty result means Lighthouse did not observe a valid WebMCP tool on the page.&lt;/p&gt;

&lt;p&gt;Third, run conversational evals. Express the same user goal in several ways and check whether the agent selects the intended tool, extracts the correct parameters and refuses or asks for clarification in invalid states.&lt;/p&gt;

&lt;p&gt;Fourth, add production telemetry. Track tool exposure, start, success, error and meaningful post-action outcomes rather than looking only at page views.&lt;/p&gt;

&lt;h2&gt;
  
  
  WebMCP and llms.txt solve different problems
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://www.xbstack.com/en/ai/llms-txt-v2-agent-readiness/?utm_source=devto&amp;amp;utm_medium=referral&amp;amp;utm_campaign=webmcp_chrome149&amp;amp;utm_content=body_link&amp;amp;ref=devto" rel="noopener noreferrer"&gt;llms.txt v2&lt;/a&gt; is about helping agents discover and understand content. WebMCP is about exposing structured actions once an agent is on an actionable page. One is primarily discovery; the other is operation. For the boundary between WebMCP and a standalone MCP Server, continue with the &lt;a href="https://www.xbstack.com/en/ai/mcp-protocol-guide/?utm_source=devto&amp;amp;utm_medium=referral&amp;amp;utm_campaign=webmcp_chrome149&amp;amp;utm_content=body_link&amp;amp;ref=devto" rel="noopener noreferrer"&gt;MCP protocol guide&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;A more complete readiness stack looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;robots / sitemap / canonical
        -&amp;gt;
llms.txt + Markdown discovery
        -&amp;gt;
clear page semantics
        -&amp;gt;
WebMCP tools where actions are useful
        -&amp;gt;
authorization / confirmation / telemetry
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;a href="https://www.xbstack.com/en/tools/agent-readiness-auditor/?utm_source=devto&amp;amp;utm_medium=referral&amp;amp;utm_campaign=webmcp_chrome149&amp;amp;utm_content=body_link&amp;amp;ref=devto" rel="noopener noreferrer"&gt;XBSTACK Agent Readiness Auditor&lt;/a&gt; evaluates these layers separately. A site is not automatically agent-ready because it has &lt;code&gt;/llms.txt&lt;/code&gt;, and registering one WebMCP tool does not make the whole site ready either.&lt;/p&gt;

&lt;h2&gt;
  
  
  Recommendation
&lt;/h2&gt;

&lt;p&gt;For a first WebMCP experiment, choose one low-risk, read-only, easily verifiable task such as documentation search, product lookup or a readiness scan. Prove the schema, tool selection, error states and telemetry before expanding into write operations.&lt;/p&gt;

&lt;p&gt;WebMCP is worth preparing for, but the technology is still experimental. Accurate version boundaries and fallbacks are more valuable than registering dozens of tools just to claim the site is "AI ready."&lt;/p&gt;




&lt;h2&gt;
  
  
  Source and related reading
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.xbstack.com/en/ai/webmcp-chrome-149-website-tools/?utm_source=devto&amp;amp;utm_medium=referral&amp;amp;utm_campaign=webmcp_chrome149&amp;amp;utm_content=original&amp;amp;ref=devto" rel="noopener noreferrer"&gt;Canonical article on XBSTACK&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.xbstack.com/en/ai/llms-txt-v2-agent-readiness/?utm_source=devto&amp;amp;utm_medium=referral&amp;amp;utm_campaign=webmcp_chrome149&amp;amp;utm_content=related_1&amp;amp;ref=devto" rel="noopener noreferrer"&gt;llms.txt v2 discovery&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.xbstack.com/en/ai/mcp-server-read-only-preflight-inspector/?utm_source=devto&amp;amp;utm_medium=referral&amp;amp;utm_campaign=webmcp_chrome149&amp;amp;utm_content=related_2&amp;amp;ref=devto" rel="noopener noreferrer"&gt;MCP read-only preflight&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.xbstack.com/en/ai/mcp-security-best-practices/?utm_source=devto&amp;amp;utm_medium=referral&amp;amp;utm_campaign=webmcp_chrome149&amp;amp;utm_content=related_3&amp;amp;ref=devto" rel="noopener noreferrer"&gt;MCP security practices&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
    </item>
    <item>
      <title>How to Configure llms.txt v2: rel=alternate, describedby, and Markdown Discovery</title>
      <dc:creator>xn</dc:creator>
      <pubDate>Mon, 31 Aug 2026 10:08:55 +0000</pubDate>
      <link>https://dev.to/xbstack/how-to-configure-llmstxt-v2-relalternate-describedby-and-markdown-discovery-1790</link>
      <guid>https://dev.to/xbstack/how-to-configure-llmstxt-v2-relalternate-describedby-and-markdown-discovery-1790</guid>
      <description>&lt;p&gt;If your site already publishes &lt;code&gt;/llms.txt&lt;/code&gt;, the August 2026 v2 update is less about adding more text and more about fixing &lt;strong&gt;discovery&lt;/strong&gt;. Previously, an agent that landed on an HTML page often had to guess whether a Markdown representation existed or whether the site exposed an llms.txt file. v2 adds explicit relationships for both cases.&lt;/p&gt;

&lt;p&gt;Use &lt;code&gt;rel="alternate" type="text/markdown"&lt;/code&gt; to point to a Markdown representation of the current page, and &lt;code&gt;rel="describedby"&lt;/code&gt; to identify the llms.txt that applies to the page. These relationships solve a machine-discovery problem. They are not a shortcut to conventional search rankings.&lt;/p&gt;

&lt;h2&gt;
  
  
  What changed in v2
&lt;/h2&gt;

&lt;p&gt;The official v2 change notes put discoverability first. A page can publish:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;link&lt;/span&gt; &lt;span class="na"&gt;rel=&lt;/span&gt;&lt;span class="s"&gt;"alternate"&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"text/markdown"&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;"/docs/example.md"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;link&lt;/span&gt; &lt;span class="na"&gt;rel=&lt;/span&gt;&lt;span class="s"&gt;"describedby"&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;"/llms.txt"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The same relationships can also be delivered through an HTTP &lt;code&gt;Link&lt;/code&gt; header. The first tells an agent that a cleaner Markdown representation is available. The second points the agent to the llms.txt that describes the relevant site or documentation scope.&lt;/p&gt;

&lt;p&gt;That is materially better than requiring every agent to guess whether &lt;code&gt;/page/&lt;/code&gt; maps to &lt;code&gt;/page.md&lt;/code&gt;, &lt;code&gt;/page.html.md&lt;/code&gt;, a content API or nothing at all.&lt;/p&gt;

&lt;h2&gt;
  
  
  How I would deploy it on a real site
&lt;/h2&gt;

&lt;p&gt;Do not start by generating a Markdown mirror for every archive and tag page. Prioritize pages where a machine-readable representation has clear utility.&lt;/p&gt;

&lt;p&gt;The first tier is developer documentation and tools: API references, MCP pages, agent documentation and tool instructions. Code, parameters and constraints survive more cleanly in Markdown than in a heavily styled application page.&lt;/p&gt;

&lt;p&gt;The second tier is high-value tutorials and troubleshooting guides. Keep the HTML version optimized for people, but expose an equivalent Markdown representation for agents. The two versions should carry the same claims and constraints; the Markdown page must not become a separate keyword-stuffing surface.&lt;/p&gt;

&lt;p&gt;The third tier is navigation and archive pages. Many of these do not need a dedicated Markdown copy at all. They simply need to lead agents toward the important content through ordinary links, sitemap coverage and a useful llms.txt file.&lt;/p&gt;

&lt;h2&gt;
  
  
  Verification checklist
&lt;/h2&gt;

&lt;p&gt;Do not stop after seeing two &lt;code&gt;&amp;lt;link&amp;gt;&lt;/code&gt; elements in source code. Verify the actual chain:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;The HTML page returns 200 and has the intended canonical URL.&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;rel=alternate&lt;/code&gt; Markdown URL returns 200 and matches the page's meaning.&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;rel=describedby&lt;/code&gt; target returns the expected llms.txt content rather than an HTML error page.&lt;/li&gt;
&lt;li&gt;robots.txt and access controls do not contradict the machine-readable paths you just exposed.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;For multilingual sites, verify that Markdown, canonical, hreflang and llms.txt scope stay language-consistent. A Chinese page that points an agent to an English-only machine representation can create a new discovery mismatch even if the HTML hreflang setup is correct.&lt;/p&gt;

&lt;h2&gt;
  
  
  What llms.txt is not
&lt;/h2&gt;

&lt;p&gt;It is not robots.txt. robots.txt primarily governs crawler access and path rules; llms.txt is closer to a curated map and context layer for agents.&lt;/p&gt;

&lt;p&gt;It is not sitemap.xml. A sitemap enumerates URLs for search systems, while llms.txt highlights context and useful machine-readable material.&lt;/p&gt;

&lt;p&gt;And it is not a documented SEO ranking switch. The practical value of v2 is reducing guessing and making machine discovery explicit. That is useful on its own and does not require inventing a ranking promise. If the page also needs to expose structured actions after discovery, the next layer is &lt;a href="https://www.xbstack.com/en/ai/webmcp-chrome-149-website-tools/?utm_source=devto&amp;amp;utm_medium=referral&amp;amp;utm_campaign=llms_txt_v2&amp;amp;utm_content=body_link&amp;amp;ref=devto" rel="noopener noreferrer"&gt;WebMCP on Chrome 149&lt;/a&gt;; discovery and operation are separate concerns.&lt;/p&gt;

&lt;h2&gt;
  
  
  Check the whole readiness chain
&lt;/h2&gt;

&lt;p&gt;The &lt;a href="https://www.xbstack.com/en/tools/agent-readiness-auditor/?utm_source=devto&amp;amp;utm_medium=referral&amp;amp;utm_campaign=llms_txt_v2&amp;amp;utm_content=body_link&amp;amp;ref=devto" rel="noopener noreferrer"&gt;XBSTACK Agent Readiness Auditor&lt;/a&gt; treats llms.txt as one part of a broader chain: machine entry points, robots and sitemap health, content discovery, Markdown/llms.txt signals, and agent-operable capabilities should be evaluated separately.&lt;/p&gt;

&lt;p&gt;A useful mental model is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Agent discovers site
  -&amp;gt; discovers llms.txt
  -&amp;gt; discovers the target page
  -&amp;gt; optionally finds the Markdown representation
  -&amp;gt; understands page constraints
  -&amp;gt; uses WebMCP or MCP only when an actionable tool layer is actually present
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That is why the two v2 link relations matter more than arguments about an ideal llms.txt word count. They turn part of agent discovery from convention and guessing into an explicit relationship controlled by the site.&lt;/p&gt;

&lt;h2&gt;
  
  
  Bottom line
&lt;/h2&gt;

&lt;p&gt;If you already publish llms.txt, add &lt;code&gt;rel=describedby&lt;/code&gt; where it helps agents locate the correct file. Where important documentation or tool pages have a stable Markdown representation, expose it with &lt;code&gt;rel=alternate type="text/markdown"&lt;/code&gt;. Then test the real HTTP responses and track whether the machine entry points are actually used.&lt;/p&gt;

&lt;p&gt;If you do not yet have llms.txt, avoid generating a giant keyword directory just because "AI SEO" is fashionable. First make the site structure and important pages coherent, then use the &lt;a href="https://www.xbstack.com/en/tools/agent-readiness-auditor/?utm_source=devto&amp;amp;utm_medium=referral&amp;amp;utm_campaign=llms_txt_v2&amp;amp;utm_content=body_link&amp;amp;ref=devto" rel="noopener noreferrer"&gt;Agent Readiness Auditor&lt;/a&gt; to identify the discovery gaps worth fixing.&lt;/p&gt;




&lt;h2&gt;
  
  
  Source and related reading
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.xbstack.com/en/ai/llms-txt-v2-agent-readiness/?utm_source=devto&amp;amp;utm_medium=referral&amp;amp;utm_campaign=llms_txt_v2&amp;amp;utm_content=original&amp;amp;ref=devto" rel="noopener noreferrer"&gt;Canonical article on XBSTACK&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.xbstack.com/en/ai/webmcp-chrome-149-website-tools/?utm_source=devto&amp;amp;utm_medium=referral&amp;amp;utm_campaign=llms_txt_v2&amp;amp;utm_content=related_1&amp;amp;ref=devto" rel="noopener noreferrer"&gt;WebMCP in Chrome 149&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.xbstack.com/en/ai/mcp-server-read-only-preflight-inspector/?utm_source=devto&amp;amp;utm_medium=referral&amp;amp;utm_campaign=llms_txt_v2&amp;amp;utm_content=related_2&amp;amp;ref=devto" rel="noopener noreferrer"&gt;MCP read-only preflight&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.xbstack.com/en/ai/ai-agent-seo-content-workflow/?utm_source=devto&amp;amp;utm_medium=referral&amp;amp;utm_campaign=llms_txt_v2&amp;amp;utm_content=related_3&amp;amp;ref=devto" rel="noopener noreferrer"&gt;Agent readiness audit&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
    </item>
    <item>
      <title>n8n Execution Stuck Running After Success: Zombie Execution When Successful Runs Are Not …</title>
      <dc:creator>xn</dc:creator>
      <pubDate>Sat, 29 Aug 2026 03:55:29 +0000</pubDate>
      <link>https://dev.to/xbstack/n8n-execution-stuck-running-after-success-zombie-execution-when-successful-runs-are-not--22lm</link>
      <guid>https://dev.to/xbstack/n8n-execution-stuck-running-after-success-zombie-execution-when-successful-runs-are-not--22lm</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;A production-focused update based on a real project: n8n execution stuck running after success? On 2.36.6, a webhook can return 200 while execution_entity stays running. This A/B …&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;If your n8n &lt;strong&gt;production webhook already returned HTTP 200 and the business action finished&lt;/strong&gt;, but the corresponding database row still looks like this long afterward:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;finished = false
status = running
stoppedAt = NULL
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;do not assume the node is still executing or the Task Runner is hung. I reproduced a much narrower failure on the official &lt;strong&gt;n8nio/n8n:2.36.6&lt;/strong&gt; image: same instance, same SQLite database, same three-node &lt;code&gt;Webhook → Set → No Operation&lt;/code&gt; workflow, with only &lt;strong&gt;Save successful production executions&lt;/strong&gt; changed.&lt;/p&gt;

&lt;p&gt;With &lt;strong&gt;Do not Save&lt;/strong&gt; (&lt;code&gt;saveDataSuccessExecution=none&lt;/code&gt;), the production webhook returned 200 but &lt;code&gt;execution_entity&lt;/code&gt; kept &lt;code&gt;finished=0 / status=running / stoppedAt=NULL&lt;/code&gt;. In the control, changing only the setting to &lt;strong&gt;Save&lt;/strong&gt; (&lt;code&gt;all&lt;/code&gt;) produced &lt;code&gt;finished=1 / status=success&lt;/code&gt; and a normal &lt;code&gt;stoppedAt&lt;/code&gt; timestamp.&lt;/p&gt;

&lt;p&gt;n8n's upstream &lt;a href="https://github.com/n8n-io/n8n/issues/37040" rel="noopener noreferrer"&gt;issue #37040&lt;/a&gt;, opened on August 25, 2026, reports the same symptom on &lt;strong&gt;n8n 2.36.6 + PostgreSQL + regular execution mode&lt;/strong&gt;. At publication time the issue is still open, marked &lt;code&gt;status:in-linear&lt;/code&gt;, with no linked fix PR. This is therefore not enough evidence to blame SQLite or PostgreSQL alone, and it is also not evidence that every execution stuck in &lt;code&gt;running&lt;/code&gt; is this bug.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F2gdirr4p4763qr7klf0a.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F2gdirr4p4763qr7klf0a.webp" alt="A successful HTTP response and completed workflow can still contradict an execution row that remains running" width="800" height="600"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Check whether you have this specific zombie execution
&lt;/h2&gt;

&lt;p&gt;The confusing part is that the workflow looks complete from the caller's perspective while the database says otherwise. This article is a good match when most of these conditions are true:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;It is a production execution such as a production Webhook.&lt;/li&gt;
&lt;li&gt;The webhook or business action already succeeded rather than a node actually blocking.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Save successful production executions&lt;/strong&gt; is set to &lt;code&gt;Do not Save&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;The matching &lt;code&gt;execution_entity&lt;/code&gt; row shows &lt;code&gt;finished=false&lt;/code&gt;, &lt;code&gt;status=running&lt;/code&gt;, and an empty &lt;code&gt;stoppedAt&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Similar successful runs keep accumulating instead of eventually closing as &lt;code&gt;success&lt;/code&gt;.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;If &lt;code&gt;runData&lt;/code&gt; is empty, the node never starts, a Code node reports &lt;code&gt;Task request timed out&lt;/code&gt;, a Schedule Trigger is not dispatching, or a container restart is required before work continues, the search phrase may still be “n8n stuck running” but the failure can be different. Upstream issue #36886, for example, describes a genuinely stuck execution path. The case here is specifically &lt;strong&gt;completed work whose persisted final state was not closed&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Minimal reproduction: change one setting
&lt;/h2&gt;

&lt;p&gt;I deliberately avoided AI Agent nodes, external APIs, database nodes, and complex expressions. Both workflows are only:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Production Webhook
      ↓
Set { ok: true }
      ↓
No Operation
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;They use the same n8n 2.36.6 instance, database and nodes. The only intended variable is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;experiment: saveDataSuccessExecution = none
control:    saveDataSuccessExecution = all
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Both production webhooks returned:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight http"&gt;&lt;code&gt;&lt;span class="k"&gt;HTTP&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="m"&gt;1.1&lt;/span&gt; &lt;span class="m"&gt;200&lt;/span&gt; &lt;span class="ne"&gt;OK&lt;/span&gt;

{"message":"Workflow was started"}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I then queried SQLite directly:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
       &lt;span class="n"&gt;workflowId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
       &lt;span class="n"&gt;finished&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
       &lt;span class="n"&gt;status&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
       &lt;span class="k"&gt;mode&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
       &lt;span class="n"&gt;startedAt&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
       &lt;span class="n"&gt;stoppedAt&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
       &lt;span class="n"&gt;storedAt&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
       &lt;span class="n"&gt;jsonSizeBytes&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;execution_entity&lt;/span&gt;
&lt;span class="k"&gt;ORDER&lt;/span&gt; &lt;span class="k"&gt;BY&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt; &lt;span class="k"&gt;DESC&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The result:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;workflowId                 finished  status   stoppedAt
-------------------------  --------  -------  -----------------------
xbstackZombieControl2366   1         success  2026-08-29 02:10:30.826
xbstackZombie2366          0         running  NULL
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fjlyheo51of9345tz4xji.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fjlyheo51of9345tz4xji.webp" alt="n8n 2.36.6 A/B comparison between Save Successful Executions none and all" width="800" height="600"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;That control matters because it removes several common confounders: the webhook itself did not fail, the workflow was not complex, and the two cases did not use different n8n versions. On this n8n 2.36.6 SQLite instance, &lt;strong&gt;changing successful execution storage from &lt;code&gt;none&lt;/code&gt; to &lt;code&gt;all&lt;/code&gt; also changed whether the execution row finalized correctly&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;The importable workflow JSON files, exact SQL output, and version matrix are published in the &lt;a href="https://github.com/xbstack/my-blog-public/tree/main/github/n8n-zombie-execution-save-none-repro" rel="noopener noreferrer"&gt;GitHub reproduction asset&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why this matters beyond a stale UI status
&lt;/h2&gt;

&lt;p&gt;If only the browser UI failed to refresh, the operational impact would be limited. Here the persisted row itself remains:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;finished = false
status = running
stoppedAt = NULL
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That can distort or complicate:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;counts of genuinely running executions;&lt;/li&gt;
&lt;li&gt;execution-history and monitoring queries;&lt;/li&gt;
&lt;li&gt;pruning and retention behavior around abnormal rows;&lt;/li&gt;
&lt;li&gt;operational scripts that check for unfinished work;&lt;/li&gt;
&lt;li&gt;database growth and execution-history governance.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So if business actions succeed while running rows accumulate, refreshing the UI is not an adequate diagnosis.&lt;/p&gt;

&lt;h2&gt;
  
  
  The safest workaround I can verify today
&lt;/h2&gt;

&lt;p&gt;As of August 29, 2026, issue #37040 has no public fix PR, so I will not claim that a particular upgrade solves it. The only mitigation directly verified by this A/B is:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;If your privacy, retention, and storage policy permits it, temporarily change Save successful production executions from Do not Save to Save, and control retention with execution pruning.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This is evidence-based rather than speculative: the &lt;code&gt;saveDataSuccessExecution=all&lt;/code&gt; control on the same three-node production webhook finalized correctly.&lt;/p&gt;

&lt;p&gt;It is not a permanent fix. Saving successful executions increases stored execution data, so evaluate retention windows, pruning configuration, and whether workflow data can contain sensitive business or user content.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fmw891eohdf5fdecbp4uc.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fmw891eohdf5fdecbp4uc.webp" alt="n8n zombie execution state mismatch and the current troubleshooting and mitigation sequence" width="800" height="600"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Do not use a direct database UPDATE as the generic fix
&lt;/h2&gt;

&lt;p&gt;A table full of rows like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;finished = 0
status = running
stoppedAt = NULL
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;makes a bulk &lt;code&gt;UPDATE execution_entity&lt;/code&gt; tempting. I do not recommend that as a generic repair.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;execution_entity&lt;/code&gt; is not just a display table. Execution state can interact with execution data, pruning, insights, metadata, and lifecycle logic. Changing &lt;code&gt;running&lt;/code&gt; to &lt;code&gt;success&lt;/code&gt; does not prove related state is consistent.&lt;/p&gt;

&lt;p&gt;If production already contains many zombie rows, a safer order is:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;take a complete database backup;&lt;/li&gt;
&lt;li&gt;verify that the save-none condition matches this reproduction;&lt;/li&gt;
&lt;li&gt;reproduce it in an isolated environment;&lt;/li&gt;
&lt;li&gt;enable successful execution saving temporarily and confirm new executions close normally;&lt;/li&gt;
&lt;li&gt;wait for upstream cleanup guidance, or design a version-specific migration only after understanding the exact schema and related rows.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  PostgreSQL versus SQLite: the evidence boundary
&lt;/h2&gt;

&lt;p&gt;The upstream #37040 reporter used PostgreSQL. This XBSTACK A/B used SQLite and produced the same:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;finished = false
status = running
stoppedAt = NULL
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That means the evidence does not support calling this PostgreSQL-specific. However, I did not complete an independent local PostgreSQL reproduction because Docker Hub repeatedly timed out while pulling &lt;code&gt;postgres:16-alpine&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The defensible summary is therefore:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;PostgreSQL: real upstream report in n8n issue #37040;&lt;/li&gt;
&lt;li&gt;SQLite: independent XBSTACK A/B reproduction;&lt;/li&gt;
&lt;li&gt;shared condition: n8n 2.36.6 with successful execution saving disabled;&lt;/li&gt;
&lt;li&gt;root cause: not publicly finalized by the upstream project yet.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  How to retest once a fix is released
&lt;/h2&gt;

&lt;p&gt;When #37040 gains a linked PR or a release explicitly fixes it, do not rely on the changelog alone. Re-run the same minimal fixture:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Webhook → Set → No Operation
saveDataSuccessExecution = none
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;and verify that successful runs no longer leave:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;finished=0 / status=running / stoppedAt=NULL
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then re-run the &lt;code&gt;saveDataSuccessExecution=all&lt;/code&gt; control to make sure normal saved successful executions still finalize correctly.&lt;/p&gt;

&lt;p&gt;The public reproduction keeps both workflow JSON fixtures and the original result so future releases can be compared against the same test rather than a moving target.&lt;/p&gt;

&lt;h2&gt;
  
  
  Bottom line
&lt;/h2&gt;

&lt;p&gt;If an n8n production workflow has already succeeded but the execution remains &lt;code&gt;running&lt;/code&gt; with &lt;code&gt;finished=false&lt;/code&gt; and &lt;code&gt;stoppedAt=NULL&lt;/code&gt;, &lt;strong&gt;check whether Save successful production executions is set to Do not Save before diagnosing a genuinely hung node&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;On n8n 2.36.6, the SQLite A/B here and the upstream PostgreSQL report point to the same execution-finalization boundary. There is no public final fix yet. The most defensible current mitigation is to evaluate enabling successful execution saving plus pruning, rather than bulk-editing execution states in the database.&lt;/p&gt;

&lt;p&gt;Related troubleshooting:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.xbstack.com/en/ai/n8n-code-node-task-runner-timeout/?utm_source=devto&amp;amp;utm_medium=referral&amp;amp;utm_campaign=article_distribution&amp;amp;utm_content=n8n-zombie-execution-save-none&amp;amp;ref=devto" rel="noopener noreferrer"&gt;n8n Code Node Task request timed out: Task Runner diagnosis&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.xbstack.com/en/ai/n8n-ai-workflow-error-handling/?utm_source=devto&amp;amp;utm_medium=referral&amp;amp;utm_campaign=article_distribution&amp;amp;utm_content=n8n-zombie-execution-save-none&amp;amp;ref=devto" rel="noopener noreferrer"&gt;n8n AI Workflow error handling and retries&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.xbstack.com/en/ai/n8n-webhook-production-hardening/?utm_source=devto&amp;amp;utm_medium=referral&amp;amp;utm_campaign=article_distribution&amp;amp;utm_content=n8n-zombie-execution-save-none&amp;amp;ref=devto" rel="noopener noreferrer"&gt;n8n production webhook URL, reverse proxy, and 404 troubleshooting&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.xbstack.com/en/ai/ai-workflow-automation-production/?utm_source=devto&amp;amp;utm_medium=referral&amp;amp;utm_campaign=article_distribution&amp;amp;utm_content=n8n-zombie-execution-save-none&amp;amp;ref=devto" rel="noopener noreferrer"&gt;AI Workflow Automation in production&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;Canonical article on XBSTACK：&lt;a href="https://www.xbstack.com/en/ai/n8n-zombie-execution-save-none/?utm_source=devto&amp;amp;utm_medium=referral&amp;amp;utm_campaign=article_distribution&amp;amp;utm_content=n8n-zombie-execution-save-none&amp;amp;ref=devto" rel="noopener noreferrer"&gt;https://www.xbstack.com/en/ai/n8n-zombie-execution-save-none/?utm_source=devto&amp;amp;utm_medium=referral&amp;amp;utm_campaign=article_distribution&amp;amp;utm_content=n8n-zombie-execution-save-none&amp;amp;ref=devto&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;标签：#AI #SoftwareEngineering #DeveloperTools #n8n #Workflow&lt;/p&gt;

</description>
    </item>
    <item>
      <title>n8n Code Node 'Task request timed out': Fix 'Not Matched to a Runner'</title>
      <dc:creator>xn</dc:creator>
      <pubDate>Wed, 26 Aug 2026 06:34:54 +0000</pubDate>
      <link>https://dev.to/xbstack/n8n-code-node-task-request-timed-out-fix-not-matched-to-a-runner-3jb1</link>
      <guid>https://dev.to/xbstack/n8n-code-node-task-request-timed-out-fix-not-matched-to-a-runner-3jb1</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;A production-focused update based on a real project: n8n Code Node reports Task request timed out / not matched to a runner. Reproduce it on 2.37.1, distinguish runner wait from J…&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;If an n8n &lt;strong&gt;Code&lt;/strong&gt; node is not throwing a JavaScript syntax error but instead waits for roughly a minute and then fails with:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Task request timed out
Your Code node task was not matched to a runner within the timeout period
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;do not start by rewriting the &lt;code&gt;return&lt;/code&gt; statement, loops, or input data. &lt;strong&gt;This error first means the Code task was not accepted by a matching Task Runner before the &lt;code&gt;N8N_RUNNERS_TASK_REQUEST_TIMEOUT&lt;/code&gt; deadline.&lt;/strong&gt; XBSTACK reproduced the exact path with official &lt;code&gt;n8nio/n8n:2.37.1&lt;/code&gt; and &lt;code&gt;n8nio/runners:2.37.1&lt;/code&gt; images in external mode: remove the runner and a one-line Code node times out; register the JavaScript runner and the same workflow passes; start the runner after the request is already waiting but before the deadline and the pending task is accepted without a manual retry. For self-hosted n8n, inspect runner registration, broker reachability, auth, image versions, worker placement and capacity. For n8n Cloud, use a minimal Code canary to separate platform runner failure from business logic, then take the execution evidence to n8n Support. &lt;strong&gt;Increasing the request timeout only extends the waiting window; it does not repair a runner that never becomes available.&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What the error actually means: this is not ordinary JavaScript execution timeout
&lt;/h2&gt;

&lt;p&gt;n8n's current Task Runner architecture has three relevant roles:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Code node / task requester
          ↓
      task broker
          ↓
 available task runner
          ↓
   execute JavaScript
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The official docs describe runners connecting to the broker over WebSocket. The Code node is the task requester: it submits a task to the broker, and an available runner accepts and executes it. If no matching runner accepts the request before the deadline, the requester receives &lt;code&gt;Task request timed out&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/..%2F..%2F..%2Fassets%2Fuploads%2Fn8n-code-node-task-runner-timeout%2Fen%2F02-requester-broker-runner.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/..%2F..%2F..%2Fassets%2Fuploads%2Fn8n-code-node-task-runner-timeout%2Fen%2F02-requester-broker-runner.webp" alt="n8n Code node requester to broker to Task Runner dispatch path, showing where the request timeout occurs when no matching runner is available" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;That is a different phase from “the runner accepted my task and the JavaScript itself ran too long.”&lt;/p&gt;

&lt;p&gt;Two current environment variables are easy to confuse:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Setting&lt;/th&gt;
&lt;th&gt;Current documented default&lt;/th&gt;
&lt;th&gt;What it limits&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;N8N_RUNNERS_TASK_REQUEST_TIMEOUT&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;60 seconds&lt;/td&gt;
&lt;td&gt;How long a task request may wait for an available runner&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;N8N_RUNNERS_TASK_TIMEOUT&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;300 seconds&lt;/td&gt;
&lt;td&gt;How long an accepted task may execute before the runner stops it&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;If the error explicitly says:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;was not matched to a runner within the timeout period
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;your first question should be &lt;strong&gt;why no runner accepted the task&lt;/strong&gt;, not how to make the JavaScript faster.&lt;/p&gt;

&lt;h2&gt;
  
  
  XBSTACK reproduction: no runner, healthy runner, and recovery while waiting
&lt;/h2&gt;

&lt;p&gt;To remove workflow complexity and Cloud-specific internals from the test, I used official Docker images on a Linux x86_64 NAS:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Docker &lt;code&gt;28.5.2&lt;/code&gt;;&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;n8nio/n8n:2.37.1&lt;/code&gt;;&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;n8nio/runners:2.37.1&lt;/code&gt;;&lt;/li&gt;
&lt;li&gt;external runner mode;&lt;/li&gt;
&lt;li&gt;default SQLite;&lt;/li&gt;
&lt;li&gt;no credentials;&lt;/li&gt;
&lt;li&gt;no external APIs;&lt;/li&gt;
&lt;li&gt;only &lt;code&gt;Manual Trigger -&amp;gt; Code&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The Code node contains one statement:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;[{&lt;/span&gt; &lt;span class="na"&gt;json&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;ok&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;source&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;xbstack-task-runner-repro&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="p"&gt;}];&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For the negative control, I shortened &lt;code&gt;N8N_RUNNERS_TASK_REQUEST_TIMEOUT&lt;/code&gt; from the current documented default of 60 seconds to &lt;strong&gt;15 seconds&lt;/strong&gt; so the failure would not take a full minute each run. The mechanism stays the same.&lt;/p&gt;

&lt;h3&gt;
  
  
  Control 1: external mode with no matching runner
&lt;/h3&gt;

&lt;p&gt;Result: &lt;strong&gt;failure after about 15.04 seconds&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;n8n logs:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;n8n Task Broker ready on 0.0.0.0, port 5679
Task request timed out
Error: Task request timed out
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The execution description says:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Your Code node task was not matched to a runner within the timeout period
(waited 15 seconds).
This indicates that the task runner is currently down, or not ready,
or at capacity, so it cannot service your task.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;Minimal Code&lt;/code&gt; execution time was about &lt;code&gt;15040 ms&lt;/code&gt;. That does &lt;strong&gt;not&lt;/strong&gt; mean the one-line JavaScript consumed 15 seconds of CPU. It means the task spent the window waiting for a JavaScript runner that never accepted it.&lt;/p&gt;

&lt;h3&gt;
  
  
  Control 2: matching JavaScript runner registers normally
&lt;/h3&gt;

&lt;p&gt;With &lt;code&gt;n8nio/runners:2.37.1&lt;/code&gt; attached as the external sidecar, the n8n log records:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Registered runner "launcher-javascript"
Registered runner "JS Task Runner"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The same Code node then returns:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"ok"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"source"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"xbstack-task-runner-repro"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Control 3: request starts first, runner starts before the deadline
&lt;/h3&gt;

&lt;p&gt;This third run is the clearest demonstration of what the request timeout means.&lt;/p&gt;

&lt;p&gt;I started the n8n CLI execution first, letting the Code task wait at the broker with no runner container active. Then I started the matching &lt;code&gt;n8nio/runners:2.37.1&lt;/code&gt; sidecar before the 15-second deadline.&lt;/p&gt;

&lt;p&gt;The workflow did not need a manual retry. After the JS runner registered, &lt;strong&gt;the already-pending task was accepted and the workflow completed after about 8.42 seconds&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/..%2F..%2F..%2Fassets%2Fuploads%2Fn8n-code-node-task-runner-timeout%2Fen%2F04-timeout-matrix.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/..%2F..%2F..%2Fassets%2Fuploads%2Fn8n-code-node-task-runner-timeout%2Fen%2F04-timeout-matrix.webp" alt="Three n8n Task Runner controls: no runner times out, healthy runner succeeds, and a pending Code request succeeds when the matching runner registers before the deadline" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The operational takeaway is straightforward:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;code&gt;N8N_RUNNERS_TASK_REQUEST_TIMEOUT&lt;/code&gt; is the “how long am I willing to wait for a runner?” window, not the “how long may my JavaScript execute?” limit.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The minimal workflow, sanitized logs and version matrix are stored in the XBSTACK reproduction asset for this issue cluster.&lt;/p&gt;

&lt;h2&gt;
  
  
  Fastest diagnosis: create one tiny Code canary first
&lt;/h2&gt;

&lt;p&gt;If the failing workflow has dozens of nodes, agents, APIs and database writes, do not debug all of that at once.&lt;/p&gt;

&lt;p&gt;Create:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Manual Trigger
  ↓
Code
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Use:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;[{&lt;/span&gt; &lt;span class="na"&gt;json&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;ok&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="p"&gt;}];&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then branch the diagnosis.&lt;/p&gt;

&lt;h3&gt;
  
  
  Case A: the minimal Code node fails with the same runner timeout
&lt;/h3&gt;

&lt;p&gt;Business logic, model API keys and input payloads are no longer your first suspects. Check:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;is the runner actually running;&lt;/li&gt;
&lt;li&gt;did it successfully register with the broker;&lt;/li&gt;
&lt;li&gt;is a JavaScript runner available, not only Python;&lt;/li&gt;
&lt;li&gt;can the runner container reach the broker;&lt;/li&gt;
&lt;li&gt;do both sides use the same auth token;&lt;/li&gt;
&lt;li&gt;are all runner concurrency slots occupied;&lt;/li&gt;
&lt;li&gt;which worker received the execution, and does that worker have its own sidecar.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Case B: the minimal Code node succeeds, but one workflow still fails
&lt;/h3&gt;

&lt;p&gt;Do not force every failure into the infrastructure bucket. Continue with:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;genuinely long-running Code;&lt;/li&gt;
&lt;li&gt;infinite loops or CPU-heavy synchronous work;&lt;/li&gt;
&lt;li&gt;very large inputs;&lt;/li&gt;
&lt;li&gt;modules missing from or not allowlisted in the runner image;&lt;/li&gt;
&lt;li&gt;a trigger-specific dispatch difference between Schedule, Webhook and Manual runs.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That final case matters because n8n #37065 is narrower than the generic timeout reproduced here: the report says the external runner is healthy, webhook/manual JavaScript runs pass, but scheduled JavaScript is not dispatched. That is a &lt;strong&gt;trigger-path/dispatch difference&lt;/strong&gt;, not proof that every runner timeout is caused by a missing sidecar.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/..%2F..%2F..%2Fassets%2Fuploads%2Fn8n-code-node-task-runner-timeout%2Fen%2F03-diagnosis-flow.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/..%2F..%2F..%2Fassets%2Fuploads%2Fn8n-code-node-task-runner-timeout%2Fen%2F03-diagnosis-flow.webp" alt="Decision tree for n8n Code node Task request timed out: minimal canary, Cloud vs self-hosted, runner registration, broker, auth, capacity and trigger-path checks" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Self-hosted n8n: check these in order before changing the timeout
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. Confirm internal vs external runner mode
&lt;/h3&gt;

&lt;p&gt;n8n currently recommends &lt;strong&gt;external mode&lt;/strong&gt; for production so &lt;code&gt;n8nio/runners&lt;/code&gt; runs as an isolated sidecar.&lt;/p&gt;

&lt;p&gt;A minimal n8n-side configuration includes:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;environment&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;N8N_RUNNERS_MODE&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;external&lt;/span&gt;
  &lt;span class="na"&gt;N8N_RUNNERS_BROKER_LISTEN_ADDRESS&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;0.0.0.0&lt;/span&gt;
  &lt;span class="na"&gt;N8N_RUNNERS_AUTH_TOKEN&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;your-shared-secret&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Runner sidecar:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;environment&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;N8N_RUNNERS_TASK_BROKER_URI&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;http://n8n:5679&lt;/span&gt;
  &lt;span class="na"&gt;N8N_RUNNERS_AUTH_TOKEN&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;your-shared-secret&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;One easy miss: the broker listens on localhost by default. In a multi-container setup, the official docs call out &lt;code&gt;N8N_RUNNERS_BROKER_LISTEN_ADDRESS=0.0.0.0&lt;/code&gt; so the sidecar can reach it.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Match the n8n and runners image versions
&lt;/h3&gt;

&lt;p&gt;The external-runner documentation explicitly says the &lt;code&gt;n8nio/runners&lt;/code&gt; image version must match the &lt;code&gt;n8nio/n8n&lt;/code&gt; version.&lt;/p&gt;

&lt;p&gt;For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;n8nio/n8n:2.37.1
n8nio/runners:2.37.1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Do not upgrade the main container and leave the sidecar pinned to an unrelated tag, then start editing the workflow first.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Look for runner registration, not only &lt;code&gt;docker ps = Up&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;A sidecar container being &lt;code&gt;Up&lt;/code&gt; proves only that the container process exists. It does not prove the JavaScript task runner has joined the broker.&lt;/p&gt;

&lt;p&gt;Useful log lines look like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Registered runner "launcher-javascript"
Registered runner "JS Task Runner"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the healthy control, n8n briefly saw only a Python offer while the pending task required JavaScript:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;No matching task offer ... (type "javascript"). Available offer types: [python]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The task proceeded only after the JS runner registered.&lt;/p&gt;

&lt;h3&gt;
  
  
  4. Verify auth and broker reachability
&lt;/h3&gt;

&lt;p&gt;The n8n container and the runners container must share the same:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;N8N_RUNNERS_AUTH_TOKEN
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The runner also needs a reachable:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;N8N_RUNNERS_TASK_BROKER_URI
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In Docker Compose that usually means a service name, for example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;http://n8n:5679
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Do not blindly use &lt;code&gt;localhost:5679&lt;/code&gt; from a separate sidecar. Inside that container, localhost points back to the runner container itself.&lt;/p&gt;

&lt;h3&gt;
  
  
  5. In Queue Mode, every execution worker needs its own sidecar
&lt;/h3&gt;

&lt;p&gt;The official docs state that each worker needs a Task Runner sidecar in Queue Mode.&lt;/p&gt;

&lt;p&gt;If manual executions pass but production executions fail, ask:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Did both executions run on the same n8n process/worker?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;If &lt;code&gt;OFFLOAD_MANUAL_EXECUTIONS_TO_WORKERS=false&lt;/code&gt;, the main instance can execute manual runs itself, so the main instance also needs an appropriate sidecar.&lt;/p&gt;

&lt;h3&gt;
  
  
  6. Check capacity before assuming the runner crashed
&lt;/h3&gt;

&lt;p&gt;The current documented default for &lt;code&gt;N8N_RUNNERS_MAX_CONCURRENCY&lt;/code&gt; is &lt;strong&gt;5&lt;/strong&gt;. If all runner slots are busy with long tasks, a new request can sit at the broker until its request timeout expires and produce the same high-level message.&lt;/p&gt;

&lt;p&gt;So the same error can reflect:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;runner container not started;&lt;/li&gt;
&lt;li&gt;runner started but never registered;&lt;/li&gt;
&lt;li&gt;auth/network prevents broker connection;&lt;/li&gt;
&lt;li&gt;no matching JavaScript/Python runner type;&lt;/li&gt;
&lt;li&gt;runner capacity is exhausted;&lt;/li&gt;
&lt;li&gt;one worker lacks a sidecar;&lt;/li&gt;
&lt;li&gt;a runner process repeatedly crashes during startup.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The message tells you &lt;strong&gt;the task was not accepted in time&lt;/strong&gt;. It does not, by itself, tell you why.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why changing 60 seconds to 300 seconds is not the first fix
&lt;/h2&gt;

&lt;p&gt;n8n's own error text points to:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;N8N_RUNNERS_TASK_REQUEST_TIMEOUT
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That can be appropriate when you already know the runners eventually become available but need more time because of cold start or short-lived saturation.&lt;/p&gt;

&lt;p&gt;It is not a root-cause fix for:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;runner container down
AUTH_TOKEN mismatch
wrong broker URI
broker bound only to localhost
JS runner crashes during startup
worker has no sidecar
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In those cases:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;60s -&amp;gt; 300s
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;only turns “fail after one minute” into “fail after five minutes.” It can also mislead operators into thinking the workflow is actively executing when the Code task has not even been accepted yet.&lt;/p&gt;

&lt;h2&gt;
  
  
  n8n Cloud: do not copy self-hosted Docker commands
&lt;/h2&gt;

&lt;p&gt;Several Cloud reports appeared on August 25-26, 2026:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;#37069: n8n Cloud 2.37.1; even a blank workflow with a minimal Code node cannot get a runner;&lt;/li&gt;
&lt;li&gt;#37062: similar 2.37.1 Cloud symptom with additional users reporting the same behavior;&lt;/li&gt;
&lt;li&gt;#37043: JavaScript Code node timeout with a Cloud 2.37.1 confirmation in comments;&lt;/li&gt;
&lt;li&gt;#36989: the same high-level timeout was also reported on Cloud 2.35.4.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That is enough to justify investigating the search problem, but &lt;strong&gt;not&lt;/strong&gt; enough to title the article “n8n 2.37.1 confirmed regression.”&lt;/p&gt;

&lt;p&gt;On August 25, GitHub releases showed the &lt;code&gt;stable&lt;/code&gt; tag at &lt;strong&gt;2.36.7&lt;/strong&gt; and the &lt;code&gt;beta&lt;/code&gt; tag at &lt;strong&gt;2.37.1&lt;/strong&gt;. Issue #37064 proposed a 2.37.x / Node 26 runner-image regression hypothesis, but a maintainer closed the issue and said they were not seeing the same behavior on their own Cloud or self-hosted instances. There is no official evidence yet that every 2.37.1 instance shares one root cause.&lt;/p&gt;

&lt;p&gt;For Cloud, the highest-value workflow is:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;create &lt;code&gt;Manual Trigger -&amp;gt; Code&lt;/code&gt;;&lt;/li&gt;
&lt;li&gt;return only &lt;code&gt;{ok:true}&lt;/code&gt;;&lt;/li&gt;
&lt;li&gt;record the n8n version;&lt;/li&gt;
&lt;li&gt;record the &lt;code&gt;waited 60/66 seconds&lt;/code&gt; detail;&lt;/li&gt;
&lt;li&gt;preserve Execution / Debug Info;&lt;/li&gt;
&lt;li&gt;if the canary fails too, send that evidence to n8n Support.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;You cannot directly inspect or restart n8n Cloud's internal runner sidecar and broker the way a self-hosted operator can.&lt;/p&gt;

&lt;h2&gt;
  
  
  Is this the same issue as the ARM64 &lt;code&gt;GLIBC_PRIVATE&lt;/code&gt; Task Runner failure?
&lt;/h2&gt;

&lt;p&gt;No.&lt;/p&gt;

&lt;p&gt;XBSTACK's existing &lt;a href="https://www.xbstack.com/en/ai/n8n-distroless-arm64-glibc-error/?utm_source=devto&amp;amp;utm_medium=referral&amp;amp;utm_campaign=article_distribution&amp;amp;utm_content=n8n-code-node-task-runner-timeout&amp;amp;ref=devto" rel="noopener noreferrer"&gt;n8n 2.33.7 distroless ARM64 &lt;code&gt;GLIBC_PRIVATE&lt;/code&gt; reproduction&lt;/a&gt; covers a different failure boundary: the Python runner process exits immediately with code 127 and a libc symbol lookup error.&lt;/p&gt;

&lt;p&gt;This article covers:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Code task submitted
↓
waiting for matching runner
↓
not accepted before deadline
↓
Task request timed out
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A runner-process crash can be one reason no runner becomes available, but the high-level &lt;code&gt;not matched to a runner&lt;/code&gt; error does not imply GLIBC or ARM64 by itself.&lt;/p&gt;

&lt;p&gt;For the full deployment baseline, see &lt;a href="https://www.xbstack.com/en/ai/self-hosted-n8n-ai-workflows/?utm_source=devto&amp;amp;utm_medium=referral&amp;amp;utm_campaign=article_distribution&amp;amp;utm_content=n8n-code-node-task-runner-timeout&amp;amp;ref=devto" rel="noopener noreferrer"&gt;Self-hosted n8n: Docker Compose, Postgres, VPS and NAS production setup&lt;/a&gt;. If the runner accepts the task and the node itself fails, retries, or needs centralized failure handling, see &lt;a href="https://www.xbstack.com/en/ai/n8n-ai-workflow-error-handling/?utm_source=devto&amp;amp;utm_medium=referral&amp;amp;utm_campaign=article_distribution&amp;amp;utm_content=n8n-code-node-task-runner-timeout&amp;amp;ref=devto" rel="noopener noreferrer"&gt;n8n Error Handling: Error Workflow, Retry On Fail, timeouts and reruns&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Practical checklist
&lt;/h2&gt;

&lt;p&gt;When you see:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Task request timed out
Your Code node task was not matched to a runner within the timeout period
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;work through this order:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;reduce to &lt;code&gt;Manual Trigger -&amp;gt; Code&lt;/code&gt;;&lt;/li&gt;
&lt;li&gt;determine whether every Code node fails;&lt;/li&gt;
&lt;li&gt;self-hosted: confirm internal vs external runner mode;&lt;/li&gt;
&lt;li&gt;verify the matching JS/Python runner actually registers;&lt;/li&gt;
&lt;li&gt;confirm n8n and runners image tags match;&lt;/li&gt;
&lt;li&gt;compare &lt;code&gt;N8N_RUNNERS_AUTH_TOKEN&lt;/code&gt; on both sides;&lt;/li&gt;
&lt;li&gt;verify &lt;code&gt;N8N_RUNNERS_TASK_BROKER_URI&lt;/code&gt; and broker listen address;&lt;/li&gt;
&lt;li&gt;in Queue Mode, confirm the execution's worker has its own sidecar;&lt;/li&gt;
&lt;li&gt;check concurrency and long-running tasks;&lt;/li&gt;
&lt;li&gt;only then decide whether a larger request timeout is justified;&lt;/li&gt;
&lt;li&gt;on Cloud, if the minimal canary still fails, escalate with evidence instead of rewriting JavaScript.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Fix status: there is no universal “upgrade to this version” answer yet
&lt;/h2&gt;

&lt;p&gt;As of 2026-08-26, this error string describes a &lt;strong&gt;symptom boundary&lt;/strong&gt;, not one single upstream bug ID.&lt;/p&gt;

&lt;p&gt;The recent Cloud cluster is worth monitoring, but the available evidence does not support either of these shortcuts:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;all 2.37.1 instances = one Task Runner regression
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;or:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;increase the request timeout = fixed
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A better production control is a tiny Code canary plus explicit checks for runner registration, broker reachability and runner capacity after deployment. That makes the next occurrence much easier to classify as platform-instance trouble, runner infrastructure trouble, or a workflow/trigger-specific problem.&lt;/p&gt;

&lt;h2&gt;
  
  
  References and reproduction assets
&lt;/h2&gt;

&lt;p&gt;Official references:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://docs.n8n.io/deploy/host-n8n/configure-n8n/set-up-task-runners/" rel="noopener noreferrer"&gt;n8n Task runners&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.n8n.io/hosting/configuration/environment-variables/task-runners/" rel="noopener noreferrer"&gt;n8n Task runner environment variables&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.n8n.io/deploy/host-n8n/configure-n8n/security/harden-task-runners/" rel="noopener noreferrer"&gt;n8n Hardening task runners&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Recent upstream reports:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/n8n-io/n8n/issues/37069" rel="noopener noreferrer"&gt;n8n #37069&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/n8n-io/n8n/issues/37062" rel="noopener noreferrer"&gt;n8n #37062&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/n8n-io/n8n/issues/37043" rel="noopener noreferrer"&gt;n8n #37043&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/n8n-io/n8n/issues/37064" rel="noopener noreferrer"&gt;n8n #37064&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/n8n-io/n8n/issues/36989" rel="noopener noreferrer"&gt;n8n #36989&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/n8n-io/n8n/issues/37065" rel="noopener noreferrer"&gt;n8n #37065&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The complete minimal workflow, no-runner log, healthy-runner control, start-while-waiting recovery control, and version matrix are public in the &lt;a href="https://github.com/xbstack/n8n-code-node-task-runner-timeout-repro" rel="noopener noreferrer"&gt;XBSTACK n8n Code Node Task Runner timeout reproduction repository&lt;/a&gt;. The source project also keeps the same assets under &lt;code&gt;experiments/n8n-code-node-task-runner-timeout-repro/&lt;/code&gt; for future version regression runs.&lt;/p&gt;




&lt;p&gt;Canonical article on XBSTACK：&lt;a href="https://www.xbstack.com/en/ai/n8n-code-node-task-runner-timeout/?utm_source=devto&amp;amp;utm_medium=referral&amp;amp;utm_campaign=article_distribution&amp;amp;utm_content=n8n-code-node-task-runner-timeout&amp;amp;ref=devto" rel="noopener noreferrer"&gt;https://www.xbstack.com/en/ai/n8n-code-node-task-runner-timeout/?utm_source=devto&amp;amp;utm_medium=referral&amp;amp;utm_campaign=article_distribution&amp;amp;utm_content=n8n-code-node-task-runner-timeout&amp;amp;ref=devto&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;标签：#AI #SoftwareEngineering #DeveloperTools #n8n #Code Node&lt;/p&gt;

</description>
    </item>
    <item>
      <title>OpenAI Assistants API Migration: Why Responses API Should Be Your New Architecture</title>
      <dc:creator>xn</dc:creator>
      <pubDate>Fri, 21 Aug 2026 07:06:55 +0000</pubDate>
      <link>https://dev.to/xbstack/openai-assistants-api-migration-why-responses-api-should-be-your-new-architecture-3gec</link>
      <guid>https://dev.to/xbstack/openai-assistants-api-migration-why-responses-api-should-be-your-new-architecture-3gec</guid>
      <description>&lt;h1&gt;
  
  
  OpenAI Assistants API Migration: Why Responses API Should Be Your New Architecture
&lt;/h1&gt;

&lt;p&gt;OpenAI Assistants API is moving toward shutdown, and projects built around Assistant, Thread and Run abstractions need a migration plan.&lt;/p&gt;

&lt;p&gt;This article explains:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;why simply replacing old APIs is risky&lt;/li&gt;
&lt;li&gt;how to separate instructions, tools, state and business logic&lt;/li&gt;
&lt;li&gt;when Responses API is enough&lt;/li&gt;
&lt;li&gt;when a custom AI Agent architecture is still required&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Full technical migration guide:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.xbstack.com/ai/openai-assistants-api-vs-custom-agent/" rel="noopener noreferrer"&gt;https://www.xbstack.com/ai/openai-assistants-api-vs-custom-agent/&lt;/a&gt;&lt;/p&gt;

</description>
    </item>
    <item>
      <title>OpenAI Zero Data Retention for AI Agents: What ZDR Does—and Does Not—Cover</title>
      <dc:creator>xn</dc:creator>
      <pubDate>Thu, 20 Aug 2026 07:21:55 +0000</pubDate>
      <link>https://dev.to/xbstack/openai-zero-data-retention-for-ai-agents-what-zdr-does-and-does-not-cover-10j8</link>
      <guid>https://dev.to/xbstack/openai-zero-data-retention-for-ai-agents-what-zdr-does-and-does-not-cover-10j8</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fyhemz9a4n7ski4e9ctwv.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fyhemz9a4n7ski4e9ctwv.webp" alt="OpenAI ZDR and AI Agent data boundaries" width="800" height="420"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This article focuses on one production misconception: enabling OpenAI Zero Data Retention does not, by itself, make an entire AI Agent system zero-retention.&lt;/p&gt;

&lt;p&gt;The easiest mistake to make with &lt;strong&gt;OpenAI Zero Data Retention (ZDR)&lt;/strong&gt; is to turn a provider-level data control into an end-to-end architecture claim:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;“If ZDR is enabled, this AI agent does not retain data anywhere.”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That is &lt;strong&gt;not&lt;/strong&gt; what the current OpenAI documentation says.&lt;/p&gt;

&lt;p&gt;As of &lt;strong&gt;August 20, 2026&lt;/strong&gt;, OpenAI's &lt;a href="https://developers.openai.com/api/docs/guides/your-data" rel="noopener noreferrer"&gt;Data Controls documentation&lt;/a&gt; says eligible customers can be approved for Zero Data Retention and configure it at the API organization or project level. With ZDR enabled, customer content is excluded from eligible abuse-monitoring logs and the &lt;code&gt;store&lt;/code&gt; parameter for &lt;code&gt;/v1/responses&lt;/code&gt; and &lt;code&gt;/v1/chat/completions&lt;/code&gt; is always treated as &lt;code&gt;false&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;A production agent, however, usually has a much larger data path:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;User / Enterprise Data
        ↓
Application / Agent Runtime
        ↓
OpenAI Responses API        ← ZDR controls part of this retention surface
        ↓
Remote MCP / Tools          ← third-party retention policy
        ↓
SaaS / Database / Files     ← business-system retention
        ↓
Agent Memory / Vector DB    ← your application state
        ↓
Trace / Audit / SIEM        ← your audit policy
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The useful question is therefore not “Does OpenAI support ZDR?” It is: &lt;strong&gt;after ZDR is enabled, where else can an enterprise agent still persist data, and how should those boundaries be governed?&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  First separate three concepts that are often conflated
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fdhk9girtq8eppl02qwgj.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fdhk9girtq8eppl02qwgj.webp" alt="store=false vs Zero Data Retention vs Data Residency" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  1. &lt;code&gt;store=false&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;This is part of endpoint/request behavior. For the Responses API, OpenAI documents application-state behavior around &lt;code&gt;store&lt;/code&gt;; when organization-level ZDR is enabled, &lt;code&gt;store&lt;/code&gt; is treated as &lt;code&gt;false&lt;/code&gt; even if a request tries to set it to &lt;code&gt;true&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Zero Data Retention
&lt;/h3&gt;

&lt;p&gt;ZDR is an &lt;strong&gt;approval-based OpenAI data control&lt;/strong&gt;, not a flag that every API key has by default. Approved customers can configure it at the organization or project level.&lt;/p&gt;

&lt;p&gt;OpenAI separates at least two storage categories:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Abuse monitoring logs&lt;/strong&gt;, which can contain prompts, responses and related metadata and are retained for up to 30 days by default under the documented policy;&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Application state&lt;/strong&gt;, which some API capabilities persist in order to perform a feature.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;ZDR changes the first category and changes application-state behavior for ZDR-eligible endpoints, but it does not automatically make every API feature or external tool zero-retention.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Data Residency
&lt;/h3&gt;

&lt;p&gt;Data Residency answers &lt;strong&gt;where&lt;/strong&gt; eligible customer content is stored or processed. ZDR answers &lt;strong&gt;whether and how long&lt;/strong&gt; relevant content is retained.&lt;/p&gt;

&lt;p&gt;They are different control planes. A regulated agent deployment may need both a residency design and a retention design.&lt;/p&gt;

&lt;h2&gt;
  
  
  The OpenAI boundaries that matter most for agent builders
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fmu722d2c92ft77cdqji6.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fmu722d2c92ft77cdqji6.webp" alt="End-to-end Zero Data Retention boundary in an AI Agent system" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The table below is more useful than a binary “supports ZDR” label.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Agent component / API capability&lt;/th&gt;
&lt;th&gt;Current documented boundary&lt;/th&gt;
&lt;th&gt;Architectural implication&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;/v1/responses&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;ZDR forces &lt;code&gt;store=false&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;Useful for stateless model calls, but tool/state choices still matter&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;/v1/chat/completions&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;ZDR forces &lt;code&gt;store=false&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;Does not imply downstream systems are zero-retention&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;/v1/conversations&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Listed as not ZDR-eligible; state persists until deletion&lt;/td&gt;
&lt;td&gt;Do not treat Conversations as stateless storage in a strict ZDR design&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;/v1/vector_stores&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Not ZDR-eligible; application state persists until deletion&lt;/td&gt;
&lt;td&gt;Vector knowledge needs its own retention policy&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;/v1/files&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Not ZDR-eligible; files persist until deletion/expiry rules&lt;/td&gt;
&lt;td&gt;Uploaded files need explicit TTL and deletion controls&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Remote MCP&lt;/td&gt;
&lt;td&gt;Third-party service&lt;/td&gt;
&lt;td&gt;Governed by the MCP provider's own retention policy&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Background Mode&lt;/td&gt;
&lt;td&gt;Response data is written to disk for roughly 10 minutes for polling&lt;/td&gt;
&lt;td&gt;Strict zero-persistence use cases need feature-level review&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Hosted Shell / Code Interpreter containers&lt;/td&gt;
&lt;td&gt;Temporary application state can exist while containers are active&lt;/td&gt;
&lt;td&gt;Sandbox lifecycle is also a data lifecycle&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Prompt Caching&lt;/td&gt;
&lt;td&gt;Encrypted KV tensors may be kept in GPU-local storage with a documented maximum 24-hour expiration boundary&lt;/td&gt;
&lt;td&gt;“No database record” does not mean “no temporary state”&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Third-party network services&lt;/td&gt;
&lt;td&gt;Third-party policy applies&lt;/td&gt;
&lt;td&gt;OpenAI ZDR cannot govern external SaaS retention&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The most consequential sentence for agent architecture is explicit in OpenAI's guide: &lt;strong&gt;MCP servers are third-party services, and data sent to an MCP server is subject to that server's data-retention policy.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;If an agent sends customer contracts, source code, financial data or internal tickets to a remote MCP server, OpenAI-side ZDR does not tell you whether that MCP provider logs, caches, forwards or stores the content.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why ZDR has to be designed with MCP security
&lt;/h2&gt;

&lt;p&gt;The MCP specification already treats tools as a security-sensitive execution surface.&lt;/p&gt;

&lt;p&gt;The current &lt;a href="https://modelcontextprotocol.io/specification/2025-11-25" rel="noopener noreferrer"&gt;MCP Specification&lt;/a&gt; notes that MCP can expose arbitrary data access and code-execution paths and therefore requires consent, authorization, data protection and tool-safety thinking. The &lt;a href="https://modelcontextprotocol.io/specification/2025-06-18/server/tools" rel="noopener noreferrer"&gt;Tools specification&lt;/a&gt; requires servers to validate inputs, implement access controls, rate-limit invocations and sanitize outputs; clients should confirm sensitive operations and log tool usage for audit.&lt;/p&gt;

&lt;p&gt;Those controls answer different questions from ZDR:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ZDR                 → OpenAI-side data-retention control
MCP Authorization   → who may invoke which tool
MCP Server Policy   → how the tool provider processes and stores data
Sandbox             → what the tool can actually affect
Audit               → whether the execution chain can be reconstructed
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;An enterprise agent needs a &lt;strong&gt;data-flow inventory&lt;/strong&gt;, not one &lt;code&gt;zdr_enabled=true&lt;/code&gt; checkbox.&lt;/p&gt;

&lt;h2&gt;
  
  
  Build a retention matrix, not a marketing claim
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fcb2c5p2d6nkxv3luc2zr.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fcb2c5p2d6nkxv3luc2zr.webp" alt="Enterprise AI Agent retention matrix" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;A practical architecture review should have a table like this:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Data flow&lt;/th&gt;
&lt;th&gt;Data type&lt;/th&gt;
&lt;th&gt;Processor&lt;/th&gt;
&lt;th&gt;Persisted?&lt;/th&gt;
&lt;th&gt;Default TTL&lt;/th&gt;
&lt;th&gt;Delete path&lt;/th&gt;
&lt;th&gt;Owner&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;User → Agent Runtime&lt;/td&gt;
&lt;td&gt;Raw request&lt;/td&gt;
&lt;td&gt;Your app&lt;/td&gt;
&lt;td&gt;Business-dependent&lt;/td&gt;
&lt;td&gt;Custom&lt;/td&gt;
&lt;td&gt;DB/API&lt;/td&gt;
&lt;td&gt;Application owner&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Runtime → OpenAI Responses&lt;/td&gt;
&lt;td&gt;Prompt/context&lt;/td&gt;
&lt;td&gt;OpenAI&lt;/td&gt;
&lt;td&gt;Feature/control-dependent&lt;/td&gt;
&lt;td&gt;Official policy&lt;/td&gt;
&lt;td&gt;Endpoint-dependent&lt;/td&gt;
&lt;td&gt;AI platform&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Agent → Remote MCP&lt;/td&gt;
&lt;td&gt;Tool args/context&lt;/td&gt;
&lt;td&gt;Third-party MCP&lt;/td&gt;
&lt;td&gt;Provider-dependent&lt;/td&gt;
&lt;td&gt;Unknown is a risk&lt;/td&gt;
&lt;td&gt;Provider policy&lt;/td&gt;
&lt;td&gt;Integration owner&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Agent → Vector DB&lt;/td&gt;
&lt;td&gt;Embeddings/chunks&lt;/td&gt;
&lt;td&gt;First/third party&lt;/td&gt;
&lt;td&gt;Usually yes&lt;/td&gt;
&lt;td&gt;Custom&lt;/td&gt;
&lt;td&gt;Delete/TTL&lt;/td&gt;
&lt;td&gt;Data owner&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Agent → Audit&lt;/td&gt;
&lt;td&gt;Tool event/approval&lt;/td&gt;
&lt;td&gt;SIEM/log store&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;Minimum necessary&lt;/td&gt;
&lt;td&gt;Retention rule&lt;/td&gt;
&lt;td&gt;Security&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;If the team cannot complete this matrix, it should not describe the system as a “zero-retention agent architecture.”&lt;/p&gt;

&lt;h2&gt;
  
  
  ZDR and audit logs are not opposites
&lt;/h2&gt;

&lt;p&gt;Another failure mode is turning “zero retention” into “turn off every useful security log.” That is not a safe production pattern.&lt;/p&gt;

&lt;p&gt;OpenAI's &lt;a href="https://openai.com/index/running-codex-safely/" rel="noopener noreferrer"&gt;Running Codex safely at OpenAI&lt;/a&gt; describes a deployment model that combines sandboxing, approvals, network policy, identity/credentials and &lt;strong&gt;agent-native telemetry and audit trails&lt;/strong&gt;. OpenTelemetry events can cover tool approval decisions, tool execution results, MCP server usage and network allow/deny decisions.&lt;/p&gt;

&lt;p&gt;The better question is:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Which content should not be retained, and which minimal security events must be retained so an incident can still be investigated?&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;A high-risk agent audit record can often store structured evidence without copying the full sensitive payload:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"actor_id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"user_or_service_hash"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"tenant_id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"tenant_123"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"tool"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"invoice.approve"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"resource_id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"invoice_***"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"decision"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"approved"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"approval_id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"appr_***"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"arguments_hash"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"sha256:..."&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"result"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"success"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"timestamp"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"..."&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That is the design tension to solve: &lt;strong&gt;data minimization without losing auditability&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why ZDR belongs inside Agent Security Infrastructure
&lt;/h2&gt;

&lt;p&gt;The broader industry signal is now stronger than a single vendor feature.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.nist.gov/publications/summary-analysis-responses-request-information-regarding-security-considerations-ai" rel="noopener noreferrer"&gt;NIST's 2026 analysis of responses on AI agent security&lt;/a&gt; says commenters widely agreed that agents introduce novel security threats and that those concerns are a barrier to adoption. NIST is also pursuing a dedicated &lt;a href="https://csrc.nist.gov/pubs/other/2026/02/05/accelerating-the-adoption-of-software-and-ai-agent/ipd" rel="noopener noreferrer"&gt;software and AI agent identity and authorization&lt;/a&gt; effort.&lt;/p&gt;

&lt;p&gt;The &lt;a href="https://genai.owasp.org/resource/owasp-top-10-for-agentic-applications-for-2026/" rel="noopener noreferrer"&gt;OWASP Top 10 for Agentic Applications 2026&lt;/a&gt; treats Tool Misuse, Identity &amp;amp; Privilege Abuse, Unexpected Code Execution, Memory &amp;amp; Context Poisoning and related agent-specific risks as a distinct security domain.&lt;/p&gt;

&lt;p&gt;The &lt;a href="https://internationalaisafetyreport.org/publication/international-ai-safety-report-2026" rel="noopener noreferrer"&gt;International AI Safety Report 2026&lt;/a&gt; places deployment-time monitoring, human oversight, chain-of-thought monitoring and sandboxing inside the technical-safeguard toolbox and explicitly emphasizes the limitations of individual safeguards and the need for defense in depth.&lt;/p&gt;

&lt;p&gt;That leads to a more durable infrastructure stack than model routing alone:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Identity
   ↓
Authorization / Policy Gate
   ↓
Approval
   ↓
Sandbox + Network Boundary
   ↓
Tool / MCP Execution
   ↓
Data Retention Policy
   ↓
Audit / Monitoring
   ↓
Incident Response / Kill Switch
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;ZDR is one component of the &lt;strong&gt;Data Retention&lt;/strong&gt; layer.&lt;/p&gt;

&lt;h2&gt;
  
  
  How I would design a ZDR-aware enterprise agent
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F4gw3ou00dpww3uc1i93l.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F4gw3ou00dpww3uc1i93l.webp" alt="ZDR-aware AI Agent production architecture" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 1: classify data before choosing controls
&lt;/h3&gt;

&lt;p&gt;At minimum, distinguish:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Public&lt;/li&gt;
&lt;li&gt;Internal&lt;/li&gt;
&lt;li&gt;Confidential&lt;/li&gt;
&lt;li&gt;Regulated / PII / PHI / Financial&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The classification determines whether data may enter the model, remote MCP, long-term memory or logs.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 2: create a data-egress record for every tool
&lt;/h3&gt;

&lt;p&gt;Track at least:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Provider&lt;/li&gt;
&lt;li&gt;Authentication identity&lt;/li&gt;
&lt;li&gt;Data categories&lt;/li&gt;
&lt;li&gt;Retention policy&lt;/li&gt;
&lt;li&gt;Region&lt;/li&gt;
&lt;li&gt;Write capability&lt;/li&gt;
&lt;li&gt;Approval requirement&lt;/li&gt;
&lt;li&gt;Audit event&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Step 3: treat unknown third-party retention as a risk
&lt;/h3&gt;

&lt;p&gt;This matters most for remote MCP. Standardized transport does not imply standardized retention. If the provider policy, contract or self-hosted boundary is unknown, do not treat it as covered by OpenAI ZDR.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 4: set explicit TTLs for every persistent state
&lt;/h3&gt;

&lt;p&gt;Review:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Application databases&lt;/li&gt;
&lt;li&gt;Agent memory&lt;/li&gt;
&lt;li&gt;Vector stores&lt;/li&gt;
&lt;li&gt;Uploaded files&lt;/li&gt;
&lt;li&gt;Traces&lt;/li&gt;
&lt;li&gt;Audit logs&lt;/li&gt;
&lt;li&gt;Temporary sandboxes&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Every state should answer: why is it needed, how long can it exist, and who can delete it?&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 5: make deletion verifiable
&lt;/h3&gt;

&lt;p&gt;A production retention policy should be executable:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;list retained objects
→ identify owner / tenant
→ delete or expire
→ verify deletion
→ retain deletion evidence
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Production checklist
&lt;/h2&gt;

&lt;p&gt;Before describing an OpenAI-powered agent as ZDR-aware, verify:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;[ ] Has the organization/project actually been approved for ZDR, rather than only using &lt;code&gt;store=false&lt;/code&gt;?&lt;/li&gt;
&lt;li&gt;[ ] Are the endpoint and features in use ZDR-eligible?&lt;/li&gt;
&lt;li&gt;[ ] Are Conversations, Vector Stores or Files used anywhere in the flow?&lt;/li&gt;
&lt;li&gt;[ ] Is Background Mode enabled?&lt;/li&gt;
&lt;li&gt;[ ] Is prompt caching enabled?&lt;/li&gt;
&lt;li&gt;[ ] Are hosted shell or Code Interpreter containers used?&lt;/li&gt;
&lt;li&gt;[ ] Is remote MCP connected, and has each third-party retention policy been reviewed?&lt;/li&gt;
&lt;li&gt;[ ] Do application memory, databases, traces and audit stores have explicit TTLs?&lt;/li&gt;
&lt;li&gt;[ ] Have Data Residency and ZDR been reviewed separately?&lt;/li&gt;
&lt;li&gt;[ ] Do logs minimize sensitive content while preserving tool/approval accountability?&lt;/li&gt;
&lt;li&gt;[ ] Is there a tested deletion and credential-revocation procedure?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If a critical item is answered with “we don't know,” the architecture is not ready to be described as zero-retention.&lt;/p&gt;

&lt;h2&gt;
  
  
  Bottom line
&lt;/h2&gt;

&lt;p&gt;Zero Data Retention is a meaningful enterprise control, but it is not a magic label that makes an entire agent stack stateless.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;A production agent's data boundary has to extend from the model API through MCP, tools, memory, sandboxes, audit systems and third-party SaaS.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;That is why the more durable enterprise opportunity is broader than model routing or token-cost management. It is &lt;strong&gt;AI Agent Security Infrastructure&lt;/strong&gt;: the control plane for identity, permissions, execution, data, audit and incident response.&lt;/p&gt;

&lt;p&gt;Continue with:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.xbstack.com/en/ai/ai-agent-security/?utm_source=devto&amp;amp;utm_medium=referral&amp;amp;utm_campaign=openai_zdr_agent_data_boundary&amp;amp;utm_content=inline_related" rel="noopener noreferrer"&gt;AI Agent Security: moving from input filtering to action constraints&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.xbstack.com/en/ai/ai-agent-tool-authorization-policy-gate/?utm_source=devto&amp;amp;utm_medium=referral&amp;amp;utm_campaign=openai_zdr_agent_data_boundary&amp;amp;utm_content=inline_related" rel="noopener noreferrer"&gt;AI Agent Tool Authorization: a per-call Policy Gate&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.xbstack.com/en/ai/mcp-security-best-practices/?utm_source=devto&amp;amp;utm_medium=referral&amp;amp;utm_campaign=openai_zdr_agent_data_boundary&amp;amp;utm_content=inline_related" rel="noopener noreferrer"&gt;MCP Security: tool permissions, roots, approvals and audit&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.xbstack.com/en/ai/openclaw-mcp-sandbox-architecture/?utm_source=devto&amp;amp;utm_medium=referral&amp;amp;utm_campaign=openai_zdr_agent_data_boundary&amp;amp;utm_content=inline_related" rel="noopener noreferrer"&gt;OpenClaw / MCP Sandbox Architecture&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.xbstack.com/en/tools/agent-security-auditor/?utm_source=devto&amp;amp;utm_medium=referral&amp;amp;utm_campaign=openai_zdr_agent_data_boundary&amp;amp;utm_content=inline_related" rel="noopener noreferrer"&gt;Agent Security Auditor: 21 production-readiness checks&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Primary references
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://developers.openai.com/api/docs/guides/your-data" rel="noopener noreferrer"&gt;OpenAI — Data controls in the OpenAI platform&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://openai.com/index/running-codex-safely/" rel="noopener noreferrer"&gt;OpenAI — Running Codex safely at OpenAI&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://internationalaisafetyreport.org/publication/international-ai-safety-report-2026" rel="noopener noreferrer"&gt;International AI Safety Report 2026&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://modelcontextprotocol.io/specification/2025-11-25" rel="noopener noreferrer"&gt;Model Context Protocol — Specification&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://modelcontextprotocol.io/specification/2025-06-18/basic/authorization" rel="noopener noreferrer"&gt;MCP — Authorization&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://modelcontextprotocol.io/specification/2025-06-18/server/tools" rel="noopener noreferrer"&gt;MCP — Tools security considerations&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.nist.gov/publications/summary-analysis-responses-request-information-regarding-security-considerations-ai" rel="noopener noreferrer"&gt;NIST — Security Considerations for AI Agents&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://genai.owasp.org/resource/owasp-top-10-for-agentic-applications-for-2026/" rel="noopener noreferrer"&gt;OWASP — Top 10 for Agentic Applications 2026&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Original article and related reading
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.xbstack.com/en/ai/openai-zero-data-retention-agent-data-boundary/?utm_source=devto&amp;amp;utm_medium=referral&amp;amp;utm_campaign=openai_zdr_agent_data_boundary&amp;amp;utm_content=original" rel="noopener noreferrer"&gt;XBSTACK original: OpenAI ZDR and AI Agent data-retention boundaries&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.xbstack.com/en/ai/ai-agent-security/?utm_source=devto&amp;amp;utm_medium=referral&amp;amp;utm_campaign=openai_zdr_agent_data_boundary&amp;amp;utm_content=related_1" rel="noopener noreferrer"&gt;AI Agent Security: Production Permissions, Sandboxing, Audit and Guardrails&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.xbstack.com/en/ai/ai-agent-tool-authorization-policy-gate/?utm_source=devto&amp;amp;utm_medium=referral&amp;amp;utm_campaign=openai_zdr_agent_data_boundary&amp;amp;utm_content=related_2" rel="noopener noreferrer"&gt;AI Agent Tool Authorization: Policy Gates, RBAC/ABAC and Resource Scopes&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.xbstack.com/en/ai/mcp-security-best-practices/?utm_source=devto&amp;amp;utm_medium=referral&amp;amp;utm_campaign=openai_zdr_agent_data_boundary&amp;amp;utm_content=related_3" rel="noopener noreferrer"&gt;MCP Security Best Practices: Authorization, Prompt Injection, Approval and Audit&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
    </item>
    <item>
      <title>n8n 2.35.3: Why $json.data.sort() Returns null</title>
      <dc:creator>xn</dc:creator>
      <pubDate>Wed, 19 Aug 2026 09:01:29 +0000</pubDate>
      <link>https://dev.to/xbstack/n8n-2353-why-jsondatasort-returns-null-41na</link>
      <guid>https://dev.to/xbstack/n8n-2353-why-jsondatasort-returns-null-41na</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fqiw8b9nme9u9gwawo65g.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fqiw8b9nme9u9gwawo65g.webp" alt="n8n 2.35.3 $json Array regression reproduction" width="800" height="420"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This is not a generic 'your array is malformed' diagnosis. I ran the same expressions in isolated branches on the official n8n 2.34.5 and 2.35.3 Docker images. Four direct mutating methods regress to null on 2.35.3, while copy-first variants remain usable.&lt;/p&gt;

&lt;p&gt;If you upgraded to &lt;strong&gt;n8n 2.35.3&lt;/strong&gt; and an Edit Fields expression such as:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{{ $json.data.sort() }}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;suddenly evaluates to:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;do not start by rewriting the input JSON. &lt;strong&gt;I reproduced the behavior locally with the official &lt;code&gt;n8nio/n8n:2.34.5&lt;/code&gt; and &lt;code&gt;n8nio/n8n:2.35.3&lt;/code&gt; Docker images. The same isolated expressions work on 2.34.5 and fail with &lt;code&gt;null&lt;/code&gt; on 2.35.3.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The regression is broader than &lt;code&gt;sort()&lt;/code&gt; in this test:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{{ $json.data.sort() }}
{{ $json.data.splice(0, 2) }}
{{ $json.data.fill("X", 0, 2) }}
{{ $json.data.copyWithin(0, 2, 4) }}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;All four returned &lt;code&gt;null&lt;/code&gt; on 2.35.3. &lt;code&gt;reverse()&lt;/code&gt; still worked. Copying the array first also worked.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Do not mutate $json.data directly
Copy first, then mutate the copy
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The shortest production containment I verified is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{{ [...$json.data].sort() }}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I also tested copy-first &lt;code&gt;splice()&lt;/code&gt;, &lt;code&gt;fill()&lt;/code&gt; and &lt;code&gt;copyWithin()&lt;/code&gt; on 2.35.3 rather than assuming they would behave like &lt;code&gt;sort()&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F6kflr2sf4tvb628vffv3.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F6kflr2sf4tvb628vffv3.webp" alt="n8n 2.35.3 production troubleshooting and upgrade guide: confirm the version, isolate the repro, identify affected methods, apply copy-first mitigation and evaluate rollback" width="800" height="420"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Why this is a version regression, not just a bad expression
&lt;/h2&gt;

&lt;p&gt;n8n issue #36540, opened on August 18, 2026, reports that several mutating Array methods called directly on &lt;code&gt;$json&lt;/code&gt; arrays started evaluating to &lt;code&gt;null&lt;/code&gt; after an upgrade from 2.34.5 to 2.35.3. The report names the same four affected methods and also notes that &lt;code&gt;reverse()&lt;/code&gt; and copy-first sorting still work.&lt;/p&gt;

&lt;p&gt;I did not treat the issue report itself as enough evidence. I pulled both official Docker images and executed the same Edit Fields expressions with the same input on both versions.&lt;/p&gt;

&lt;p&gt;The comparison environment was:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Item&lt;/th&gt;
&lt;th&gt;Control&lt;/th&gt;
&lt;th&gt;Regression&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;n8n&lt;/td&gt;
&lt;td&gt;2.34.5&lt;/td&gt;
&lt;td&gt;2.35.3&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Docker image&lt;/td&gt;
&lt;td&gt;&lt;code&gt;n8nio/n8n:2.34.5&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;n8nio/n8n:2.35.3&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Node.js&lt;/td&gt;
&lt;td&gt;v24.18.0&lt;/td&gt;
&lt;td&gt;v24.18.1&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Database&lt;/td&gt;
&lt;td&gt;default SQLite&lt;/td&gt;
&lt;td&gt;default SQLite&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Execution&lt;/td&gt;
&lt;td&gt;n8n CLI &lt;code&gt;execute&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;n8n CLI &lt;code&gt;execute&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Edit Fields&lt;/td&gt;
&lt;td&gt;same node shape&lt;/td&gt;
&lt;td&gt;same node shape&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Every method was given its own independent branch with this input:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"data"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="s2"&gt;"Mango"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="s2"&gt;"Apple"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="s2"&gt;"Kiwi"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="s2"&gt;"Orange"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="s2"&gt;"Blueberry"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="s2"&gt;"Banana"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="s2"&gt;"Peach"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="s2"&gt;"Grape"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="s2"&gt;"Pineapple"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="s2"&gt;"Strawberry"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That isolation matters. My first combined-field workflow put several mutating expressions in one Edit Fields node. On 2.34.5 those methods really mutate the shared input array, so one field can change what a later field sees. The isolated workflow removes that source of noise and is the authoritative version matrix.&lt;/p&gt;

&lt;h2&gt;
  
  
  2.34.5 versus 2.35.3
&lt;/h2&gt;

&lt;p&gt;The isolated results:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fo8lar8fstuuiwzg7xj6e.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fo8lar8fstuuiwzg7xj6e.webp" alt="n8n 2.34.5 versus 2.35.3 Array regression matrix: sort, splice, fill and copyWithin return null on 2.35.3 while reverse remains normal" width="800" height="420"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Expression&lt;/th&gt;
&lt;th&gt;n8n 2.34.5&lt;/th&gt;
&lt;th&gt;n8n 2.35.3&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;$json.data.sort()&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;sorted array&lt;/td&gt;
&lt;td&gt;&lt;code&gt;null&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;$json.data.splice(0, 2)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;['Mango','Apple']&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;null&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;$json.data.fill('X', 0, 2)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;filled array&lt;/td&gt;
&lt;td&gt;&lt;code&gt;null&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;$json.data.copyWithin(0, 2, 4)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;mutated array&lt;/td&gt;
&lt;td&gt;&lt;code&gt;null&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;$json.data.reverse()&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;works&lt;/td&gt;
&lt;td&gt;works&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;[...$json.data].sort()&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;works&lt;/td&gt;
&lt;td&gt;works&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;$json.data.slice().sort()&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;works&lt;/td&gt;
&lt;td&gt;works&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Three details narrow the failure surface:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;The input and node shape are unchanged; only the n8n version changes.&lt;/li&gt;
&lt;li&gt;Not every mutating method is affected; &lt;code&gt;reverse()&lt;/code&gt; works on 2.35.3.&lt;/li&gt;
&lt;li&gt;Sorting itself still works when it is performed on a copied array.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;So the observable boundary is not “JavaScript arrays are broken.” It is that &lt;strong&gt;some mutating methods called directly on arrays exposed by &lt;code&gt;$json&lt;/code&gt; are handled differently in 2.35.3&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;I am deliberately stopping there on root cause. Until upstream maintainers publish a fix or a concrete internal change, it would be speculation to claim that a particular proxy, immutability guard, expression sandbox or serialization path is the cause.&lt;/p&gt;

&lt;h2&gt;
  
  
  Tested workaround: copy first, then mutate
&lt;/h2&gt;

&lt;p&gt;For a production workflow, I prefer the smallest reversible change first.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fp97asg5w2k4tukoky8u6.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fp97asg5w2k4tukoky8u6.webp" alt="n8n 2.35.3 temporary fix: avoid mutating $json.data directly, copy the array first, then call sort, splice, fill or copyWithin" width="800" height="420"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  sort()
&lt;/h3&gt;

&lt;p&gt;Before:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{{ $json.data.sort() }}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Use:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{{ [...$json.data].sort() }}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;or:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{{ $json.data.slice().sort() }}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Both passed on 2.35.3.&lt;/p&gt;

&lt;h3&gt;
  
  
  splice()
&lt;/h3&gt;

&lt;p&gt;Before:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{{ $json.data.splice(0, 2) }}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Use:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{{ [...$json.data].splice(0, 2) }}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;My 2.35.3 run returned:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"Mango"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Apple"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Remember that JavaScript &lt;code&gt;splice()&lt;/code&gt; returns the removed elements. If your business logic needs the remaining array, changing only the regression workaround does not change that JavaScript semantic.&lt;/p&gt;

&lt;h3&gt;
  
  
  fill()
&lt;/h3&gt;

&lt;p&gt;Before:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{{ $json.data.fill("X", 0, 2) }}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Use:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{{ [...$json.data].fill("X", 0, 2) }}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Verified 2.35.3 output:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"X"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"X"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Kiwi"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Orange"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Blueberry"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Banana"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Peach"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Grape"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Pineapple"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Strawberry"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  copyWithin()
&lt;/h3&gt;

&lt;p&gt;Before:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{{ $json.data.copyWithin(0, 2, 4) }}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Use:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{{ [...$json.data].copyWithin(0, 2, 4) }}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Verified 2.35.3 output:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"Kiwi"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Orange"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Kiwi"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Orange"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Blueberry"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Banana"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Peach"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Grape"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Pineapple"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Strawberry"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;These are runtime results from the same official 2.35.3 image, not untested equivalents inferred from the &lt;code&gt;sort()&lt;/code&gt; workaround.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why copy-first is a better expression boundary anyway
&lt;/h2&gt;

&lt;p&gt;n8n expressions reference data produced by previous nodes. Calling &lt;code&gt;sort()&lt;/code&gt;, &lt;code&gt;splice()&lt;/code&gt;, &lt;code&gt;fill()&lt;/code&gt; or &lt;code&gt;copyWithin()&lt;/code&gt; directly on &lt;code&gt;$json.data&lt;/code&gt; mixes two concerns: reading the current input and mutating the object that exposes that input.&lt;/p&gt;

&lt;p&gt;That can make workflows harder to reason about even without this regression. The combined-field control on 2.34.5 demonstrated the risk directly: one mutating field can change the array that later expressions read.&lt;/p&gt;

&lt;p&gt;Copy-first expressions separate the requested result from the input object:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{{ [...$json.data].sort() }}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For a simple string array, that boundary is clear. For arrays of nested objects, remember that spread syntax performs a shallow copy, so deeper mutation still requires its own design decision.&lt;/p&gt;

&lt;h2&gt;
  
  
  Should you downgrade to 2.34.5?
&lt;/h2&gt;

&lt;p&gt;A rollback is not automatically the safest first move.&lt;/p&gt;

&lt;p&gt;If only a handful of Edit Fields expressions are affected, replacing direct mutation with copy-first expressions is usually a smaller and more reversible production change. Search your workflows for calls such as:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;.sort(
.splice(
.fill(
.copyWithin(
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;and focus on expressions that call them directly on &lt;code&gt;$json.xxx&lt;/code&gt; arrays.&lt;/p&gt;

&lt;p&gt;If a large number of workflows depend on this pattern and you cannot regression-test them quickly, a controlled rollback may be reasonable. But n8n rollback decisions also involve database migrations, other node changes, credentials and your deployment process. Back up the database and workflows and test 2.34.5 before changing production.&lt;/p&gt;

&lt;h2&gt;
  
  
  A practical 2.35.3 triage sequence
&lt;/h2&gt;

&lt;p&gt;If your symptom matches this article:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Confirm the runtime is actually 2.35.3, including workers if you run a distributed setup.&lt;/li&gt;
&lt;li&gt;Keep the failing expression and input as a control.&lt;/li&gt;
&lt;li&gt;Change only the array access to a copy-first form and rerun the same item.&lt;/li&gt;
&lt;li&gt;If the copy-first version works, check whether the expression uses &lt;code&gt;sort&lt;/code&gt;, &lt;code&gt;splice&lt;/code&gt;, &lt;code&gt;fill&lt;/code&gt; or &lt;code&gt;copyWithin&lt;/code&gt; directly on &lt;code&gt;$json&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Restore the smallest failing point before refactoring the rest of the workflow.&lt;/li&gt;
&lt;li&gt;Audit other workflows for the same direct-mutation pattern.&lt;/li&gt;
&lt;li&gt;When upstream ships a fix, remove the workaround in a test instance first and compare outputs before changing production.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  This is not the same n8n bug as yesterday's HTTP Request stream issue
&lt;/h2&gt;

&lt;p&gt;XBSTACK published a separate &lt;a href="https://www.xbstack.com/en/ai/n8n-http-request-raw-body-response-stream/?utm_source=devto&amp;amp;utm_medium=referral&amp;amp;utm_campaign=n8n_2353_array_null_regression&amp;amp;utm_content=related_link" rel="noopener noreferrer"&gt;n8n HTTP Request Raw Body / &lt;code&gt;_readableState&lt;/code&gt; troubleshooting article&lt;/a&gt; yesterday. The product is the same; the search intent is not.&lt;/p&gt;

&lt;p&gt;That issue lives in the &lt;strong&gt;HTTP Request Raw Body + Response Format path&lt;/strong&gt; and exposes a stream-shaped object instead of parsed JSON.&lt;/p&gt;

&lt;p&gt;This issue lives in &lt;strong&gt;Edit Fields expression evaluation&lt;/strong&gt; and returns &lt;code&gt;null&lt;/code&gt; for several direct &lt;code&gt;$json&lt;/code&gt; Array mutations after the 2.35.3 upgrade.&lt;/p&gt;

&lt;p&gt;They therefore deserve separate URLs and separate reproduction assets. For broader workflow failure patterns, see the &lt;a href="https://www.xbstack.com/en/ai/n8n-ai-workflow-error-handling/?utm_source=devto&amp;amp;utm_medium=referral&amp;amp;utm_campaign=n8n_2353_array_null_regression&amp;amp;utm_content=related_link" rel="noopener noreferrer"&gt;n8n workflow error-handling guide&lt;/a&gt; and the &lt;a href="https://www.xbstack.com/en/ai/workflow/?utm_source=devto&amp;amp;utm_medium=referral&amp;amp;utm_campaign=n8n_2353_array_null_regression&amp;amp;utm_content=related_link" rel="noopener noreferrer"&gt;Workflow hub&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Evidence boundary and upstream tracking
&lt;/h2&gt;

&lt;p&gt;As of August 19, 2026, I can state the following with local runtime evidence:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Upstream issue #36540 reports the same 2.35.3 regression.&lt;/li&gt;
&lt;li&gt;XBSTACK reproduced the version difference with official 2.34.5 and 2.35.3 Docker images.&lt;/li&gt;
&lt;li&gt;Direct &lt;code&gt;sort/splice/fill/copyWithin&lt;/code&gt; calls on &lt;code&gt;$json.data&lt;/code&gt; return &lt;code&gt;null&lt;/code&gt; on 2.35.3 in the isolated Edit Fields test.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;reverse()&lt;/code&gt; does not show the same failure.&lt;/li&gt;
&lt;li&gt;Copy-first versions of all four affected methods pass on 2.35.3.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I am not claiming that a specific internal commit is the root cause, and I am not predicting a fix version before upstream publishes one.&lt;/p&gt;

&lt;p&gt;Primary references:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/n8n-io/n8n/issues/36540" rel="noopener noreferrer"&gt;n8n issue #36540: Regression in 2.35.3: several mutating Array methods on $json return null&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.n8n.io/data/data-mapping/data-mapping-ui/" rel="noopener noreferrer"&gt;n8n docs: Referencing data in the UI&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;When upstream ships a confirmed fix, this page should be updated with the affected/fixed version matrix instead of creating another duplicate troubleshooting URL.&lt;/p&gt;




&lt;p&gt;Canonical article and future updates:&lt;br&gt;
&lt;a href="https://www.xbstack.com/en/ai/n8n-2353-json-array-methods-return-null/?utm_source=devto&amp;amp;utm_medium=referral&amp;amp;utm_campaign=n8n_2353_array_null_regression&amp;amp;utm_content=article_body" rel="noopener noreferrer"&gt;https://www.xbstack.com/en/ai/n8n-2353-json-array-methods-return-null/?utm_source=devto&amp;amp;utm_medium=referral&amp;amp;utm_campaign=n8n_2353_array_null_regression&amp;amp;utm_content=article_body&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Public minimal reproduction:&lt;br&gt;
&lt;a href="https://github.com/xbstack/n8n-2353-json-array-null-repro" rel="noopener noreferrer"&gt;https://github.com/xbstack/n8n-2353-json-array-null-repro&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Upstream issue:&lt;br&gt;
&lt;a href="https://github.com/n8n-io/n8n/issues/36540" rel="noopener noreferrer"&gt;https://github.com/n8n-io/n8n/issues/36540&lt;/a&gt;&lt;/p&gt;

</description>
    </item>
  </channel>
</rss>
