With response streaming enabled, if the client disconnects (browser refresh) while the AI Agent is still streaming, the execution is aborted and shows { “isArtificialRecoveredEventItem”: true } with “Execution stopped at this node.” I’d like the execution to finish server-side even if the client disconnects, while keeping streaming on.
Minimal reproduction (vanilla n8n, no custom nodes)
Chat Trigger (or Webhook with Response Mode: Streaming).
AI Agent node with enableStreaming: true, connected to:
any Chat Model (e.g. OpenAI Chat Model),
any one tool that takes a few seconds (e.g. an HTTP Request tool hitting a slow endpoint — anything that keeps the agent busy long enough to refresh).
Open the built-in chat, send a message that makes the agent call the tool.
Refresh the page immediately, while it’s still streaming.
Open the execution → it’s stopped, AI Agent output = { “isArtificialRecoveredEventItem”: true }.
Environment
n8n: Cloud, version 2.27.4
AI Agent node v3.1, Webhook v2.1 (responseMode: streaming)
Expected vs actual
Expected: client losing the stream shouldn’t abort the run; the agent (and any tool side-effects) should complete server-side.
Actual: the run is aborted the moment the streaming connection drops → recovered/artificial item.
What I’ve tried
Disabling enableStreaming on the AI Agent avoids it — but then there’s no streaming (disabling streaming on either node falls back to request-response).
I know the immediate-response / two-webhook async pattern exists, but that drops live streaming.
Question
Is there a supported way to decouple execution lifetime from the streaming HTTP connection — i.e. keep streaming enabled but let the execution complete (not abort) when the client disconnects mid-stream? Any setting, or recommended pattern?
Bạn muốn tôi:
Export 1 workflow tối giản (Chat Trigger + AI Agent + 1 tool giả lập chậm + LLM) thành JSON để bạn đính kèm — repro được ngay, tăng mạnh khả năng được giúp?
Hay giữ bản này và bạn tự điền version + đính ảnh?
With response streaming enabled, if the client disconnects (browser refresh) while the AI Agent is still streaming, the execution is aborted and shows { “isArtificialRecoveredEventItem”: true } with “Execution stopped at this node.” I’d like the execution to finish server-side even if the client disconnects, while keeping streaming on.
Minimal reproduction (vanilla n8n, no custom nodes)
Chat Trigger (or Webhook with Response Mode: Streaming).
AI Agent node with enableStreaming: true, connected to:
any Chat Model (e.g. OpenAI Chat Model),
any one tool that takes a few seconds (e.g. an HTTP Request tool hitting a slow endpoint — anything that keeps the agent busy long enough to refresh).
Open the built-in chat, send a message that makes the agent call the tool.
Refresh the page immediately, while it’s still streaming.
Open the execution → it’s stopped, AI Agent output = { “isArtificialRecoveredEventItem”: true }.
Environment
n8n: Cloud, version <điền version>
AI Agent node v3.1, Webhook v2.1 (responseMode: streaming)
Expected vs actual
Expected: client losing the stream shouldn’t abort the run; the agent (and any tool side-effects) should complete server-side.
Actual: the run is aborted the moment the streaming connection drops → recovered/artificial item.
What I’ve tried
Disabling enableStreaming on the AI Agent avoids it — but then there’s no streaming (disabling streaming on either node falls back to request-response).
I know the immediate-response / two-webhook async pattern exists, but that drops live streaming.
@sawsew467 nenhum botão integrado para nenhum dos três, streaming vincula a execução à conexão ativa então uma desconexão derruba tudo (esse item recuperado é o marcador genérico “killed before finishing” do n8ns, não é um OOM real), e não há nada documentado para desacoplá-lo ou reconectá-lo. o fix é não rodar o trabalho que deve sobreviver na execução em stream, jogar o agent + memory write em uma execução separada non-streaming que termine server-side, e deixar o cliente re-ler o histórico no reload. e tirar tools com side-effects como send email do stream pra eles não poderem disparar em um turno que nunca persiste.
Esse marcador isArtificialRecoveredEventItem é um sinal de que a execução travou em vez de ser cancelada de forma limpa. Quando o navegador se desconecta, o socket TCP fecha, e a próxima chamada res.write() dentro do servidor de streaming de chunks do n8n lança um erro EPIPE. Isso se propaga pela cadeia de callbacks do LangChain até o mecanismo de fluxo de trabalho, que causa o travamento da execução no meio do caminho. O serviço de recuperação então preenche esse espaço reservado artificial para qualquer nó que tenha começado mas nunca persistiu sua saída.
Então a conexão SSE e a execução do lado do servidor estão acopladas arquitetonicamente na implementação de streaming atual do n8n. Não há flag de configuração para desacoplá-las.
Suas opções reais:
1. Desabilitar streaming no nó AI Agent: o que você já tentou, mas vale a pena nomear claramente: a execução é executada até o final no servidor com zero risco de desconexão, e a resposta completa retorna quando o fluxo de trabalho termina. O custo de UX é real, mas a execução é confiável.
2. Responder imediatamente, depois fazer polling: Use um nó Webhook configurado como “Respond Immediately” (Responder Imediatamente). Ele retorna um executionId imediatamente, o fluxo de trabalho é executado totalmente em background sem nenhuma resposta HTTP anexada (nenhuma conexão SSE para cair), e o cliente faz polling em GET /api/v1/executions/{id} para obter o resultado. Ferramentas lentas sempre serão concluídas. Você perde a UX de streaming, mas ganha execução determinística. Na Cloud você fica dentro do timeout de execução de 5 minutos enquanto seu HTTP Request não for absurdamente lento.
3. Modo Queue com workers: apenas self-hosted, não disponível na Cloud. Mesmo assim, não está claro se falhas de escrita de streaming no processo principal se desacoplam totalmente do estado de execução do worker.
Para sua configuração específica, a opção 2 é provavelmente o melhor caminho se você precisa que as ferramentas sempre se completem. A UX de polling é menos elegante que SSE, mas muito mais previsível do que contar que o cliente permaneça conectado.
Se streaming com tolerância a desconexão é crítico, isso exigiria uma mudança em como o n8n lida com erros de escrita SSE, especificamente não propagando-os de volta para o mecanismo de execução.
Ambas as respostas acima estão certas que o streaming de agente integrado do n8n vincula o trabalho à requisição ao vivo, então uma desconexão derruba a execução e não há flag para desacoplá-los hoje. Mas você ainda pode obter UX de streaming e conclusão garantida no servidor ao mesmo tempo. O truque é parar de fazer streaming através da requisição do n8n e mover o stream para um canal que o cliente se inscreve independentemente.
Uma forma que funciona:
Trate a turn como um job em background durável. Pegue a opção 2 de PurveshGandhi como base: o webhook responde imediatamente com um id de turn, o agente executa até o final no servidor sem SSE anexado, e a escrita de memória acontece não importa o quê. Isso sozinho torna o trabalho que precisa sobreviver à prova de desconexão.
Recupere o streaming escrevendo chunks em um canal externo, não na resposta HTTP. Conforme a turn produz saída, escreva para algo que o navegador possa se inscrever por conta própria: uma linha realtime do Supabase, Redis pub/sub, Ably, ou até uma coluna partial_response que o cliente consulta algumas vezes por segundo. O navegador lê desse canal, nunca do SSE do n8n. Agora uma desconexão apenas interrompe o lado da leitura, a execução continua rodando, e ao recarregar o cliente se reinscreve e se atualiza a partir da partial armazenada. Essa é a resposta de ter ambos: o trabalho está vinculado ao job, o stream está vinculado ao armazenamento.
Se a suavidade em nível de token realmente importar, faça o streaming do modelo em um streamer fino fora do n8n (uma pequena edge function que faz streaming de tokens de modelo para o cliente e envia a transcrição final de volta ao n8n para a escrita de memória durável e quaisquer ferramentas). O n8n permanece o sistema de registro, a edge function é apenas o tubo.
Mais um, no espírito do ponto de achamm sobre ferramentas com efeitos colaterais: mantenha todos os efeitos colaterais, envie email, escreva no CRM, qualquer coisa que custe dinheiro, protegida atrás da turn confirmada e identificada pelo id da turn, para que uma turn repetida ou inacabada não a dispare duas vezes. Streaming nunca deve ser o que decide se um efeito colateral aconteceu.
Então você na verdade não precisa escolher. Vincule a execução a um job durável, vincule o stream a um canal externo, e a desconexão do cliente deixa de importar.
Oi
Acho que entendi o problema — esse é um case extremamente comum com n8n AI Agent + streaming quando a conexão do cliente cai (atualização do navegador / reconexão).
O que está acontecendo aqui é basicamente:
o ciclo de vida da stream está muito vinculado ao contexto de execução, então quando o frontend se desconecta, a execução do backend é interrompida ou reidratada incorretamente.
Eu trataria isso como dois ciclos de vida que estão atualmente acoplados:
ciclo de vida de streaming do cliente
A conexão navegador/cliente quer tokens/eventos parciais agora.
ciclo de vida de execução do servidor
A execução do agente pode precisar terminar mesmo que o cliente se desconecte.
Se esses estiverem vinculados à mesma conexão HTTP, uma desconexão pode se tornar um sinal de cancelamento de execução. Para agentes de longa duração, eu normalmente os desacoplaria:
a requisição inicia um job e retorna um job_id;
o workflow no servidor continua independentemente;
o endpoint de stream apenas se inscreve em eventos do job;
se o stream se desconectar, o job continua rodando;
o cliente pode se reconectar com job_id e buscar o status/eventos/resultado atual;
os estados terminais são success, failed, cancelled_by_user, timed_out.
A distinção importante é “cliente desapareceu” vs “usuário cancelou intencionalmente.” Esses devem ser estados separados.
Se o caminho de streaming atual do n8n vincula desconexão a abort, o padrão mais seguro é colocar o agente de longa duração atrás de uma camada de job durável e tratar o streaming como um observador, não como o proprietário da execução.
Uma pergunta não sensível: você precisa que o navegador receba cada token intermediário, ou é suficiente fazer stream do status/eventos e buscar o resultado final quando o job se completa?
Esta é uma limitação arquitetônica atual do n8n: quando o streaming está habilitado, o ciclo de vida da execução é vinculado à conexão push, então uma desconexão sinaliza um aborto. Não há uma configuração integrada para desacoplá-los neste momento.
O padrão funcionando mais próximo no n8n hoje: use um Webhook regular (sem streaming) como ponto de entrada, retorne imediatamente um job_id ao cliente usando o nó “Respond to Webhook”, depois dispare o trabalho real do agente como um sub-workflow usando “Execute Workflow” configurado para o modo “Run in Background”. O cliente faz polling de um segundo webhook GET com o job_id para buscar o resultado assim que for escrito em um banco de dados ou armazenamento de dados estático. Você perde o streaming de tokens em tempo real, mas a execução do agente é concluída independentemente do estado do cliente - o que parece ser o que você realmente precisa aqui.