Descreva o problema/erro/pergunta
Olá pessoal, estou enfrentando um problema muito estranho com o Node YouTube ao tentar criar dinamicamente uma playlist. Funciona perfeitamente quando clico manualmente em “Execute Step” dentro da interface do n8n, mas no momento em que o workflow é executado em produção (gatilho automatizado/ativo), ele falha completamente com um erro 400 Bad Request.
Configuração e Setup do Node
O Comportamento
-
No Teste Manual da Interface: A expressão é resolvida perfeitamente para uma string limpa: "Zedd, Bright Lights - Follow You Down - Keys N Krates Remix" (cerca de 77 caracteres, bem dentro do limite de 150 caracteres do YouTube). O nó de entrada (Match) passa ambos os campos JSON e dados de informações binárias.
-
Na Execução em Produção: A mesma estrutura de dados entra, a string de título deveria ser idêntica, mas o nó gera o seguinte erro de API.
O Que Já Verifiquei/Tentei:
-
Google Cloud Console App: Configurado para modo Production (não em Testing/Sandbox).
-
Privacy Status: Tentei tanto Public quanto Private/Unlisted. Mesmo erro em ambos em produção.
-
Limites de Caracteres: O título tem apenas ~77 caracteres.
-
Caracteres Especiais: Tentei usar uma regex rigorosa para remover tudo exceto caracteres alfanuméricos básicos, mas o erro 400 persiste.
-
Presença do Canal: A conta do Google possui um canal YouTube ativo e totalmente criado, e outros nós (como upload de vídeo) funcionam bem.
Por que o n8n se comporta de forma diferente entre a execução manual e uma execução de produção automatizada ao analisar ou enviar este payload para o YouTube? Alguém tem ideias sobre como depurar ou contornar isso?
Compartilhe seu workflow
Compartilhe a saída retornada pelo último nó
Informações sobre sua configuração do n8n
- versão n8n: v2.23.2
- Banco de dados (padrão: SQLite): padrão
- configuração n8n EXECUTIONS_PROCESS (padrão: own, main): main
- Executando n8n via (Docker, npm, n8n cloud, app desktop): Docker
- Sistema operacional: Raspberry Pi OS 64-bit Debian 13 trixie (aarch64)
O Teste Manual de UI pode ocultar a incompatibilidade porque é executado contra o item atualmente selecionado no editor. Na execução de produção que falhou, a única entrada que importa é o painel de entrada diretamente no nó YouTube, não o nó Match a montante.
Verifique esse painel para o item que o nó YouTube realmente recebeu. Se artist_name / album_name estiverem ausentes lá ou vindo de um item emparelhado, congele o título em um nó Set/Edit Fields logo antes do YouTube e mapeie o título da playlist desse novo campo. Se o campo já for uma string simples lá, publique esse item de entrada do nó YouTube com redação mais um corpo de resposta 400 completo.
Ei, obrigado pela sua resposta. Reestruturei o workflow para usar o nó Merge no modo combine (como visto no anexo) para garantir que os dados binários e os metadados JSON permaneçam perfeitamente sincronizados ao longo do pipeline.
Então, tudo parecia perfeito até a execução aqui. Considerando sua resposta, pensei que poderia aplicar a mesma situação para upload de vídeos. Porém, não funcionou. Também alterei o modo do meu nó merge para combine. Infelizmente, não funcionou. Você pode encontrar o status mais recente do meu workflow abaixo.
Obrigado. As capturas de tela ainda não mostram a entrada do nó YouTube que falhou, então Merge mode é um passo anterior à coisa que decide isso.
Abra a execução de produção que falhou, clique no nó YouTube em si e copie um item JSON de entrada editado desse nó mais o corpo completo da resposta 400. Se esse nó já recebe uma string de título de playlist simples, a próxima verificação é o payload exato que o YouTube rejeita; se não receber, a correção está imediatamente antes do YouTube.
Você está absolutamente certo. O fix do nó Merge resolveu o problema de Video Upload, mas o erro inicial da Playlist 400 estava de fato acontecendo upstream, antes mesmo do nó Merge ser executado.
Como o workflow agora está rodando perfeitamente em produção depois que reconstruí aquela seção, voltei aos logs de execução antigos que falharam para pegar exatamente o que o nó YouTube Playlist recebeu em seu painel de input durante o crash, só para satisfazer a análise de causa raiz.
Aqui está o JSON redatado do painel INPUT do nó YouTube Playlist que falhou:
{
"json": {
"album_name": "Follow You Down - Keys N Krates Remix",
"artist_name": "Zedd, Bright Lights"
}
}
E a expression no campo Title era:
{{ $json.artist_name }} - {{ $json.album_name }} (Full Release)
Mesmo que tenha se resolvido visualmente bem na preview da UI, naquela execução específica em produção, o n8n estava perdendo o contexto de item pareado porque o stream de entrada vinha diretamente de um nó binary multi-item sem ancoragem explícita de índice de item (como usar .item.json). Então o YouTube provavelmente estava recebendo uma string de payload vazia ou malformada por baixo dos panos.
Agora, tenho algumas perguntas:
1- Você disse que:
“Manual UI Test pode esconder a disparidade porque roda contra o item atualmente selecionado no editor.”
Então, como posso ir testar isso? É sempre em produção ou existe algum ambiente especial?
2- Quando comecei a executar o workflow (publicado), ele começa perfeitamente, mas alguns erros começam a ocorrer sem motivo aparente. Por exemplo, erros relacionados a expressions etc. Por que isso acontece mesmo não havendo problema?
Obrigado.
Bom trabalho de detetive investigando os antigos logs de execução.
Sobre a pergunta 1 — testar o comportamento de produção sem um trigger ativo:
A forma mais limpa é usar o botão “Test workflow” (o ícone de play no topo da canvas quando o workflow está ativo/publicado). Isso executa o workflow exatamente como em produção, usando o trigger real — para workflows baseados em webhook, coloca o n8n em um estado de escuta para uma chamada real recebida. Você também pode fazer um POST manual de um payload de teste para sua URL de webhook usando uma ferramenta como Postman ou curl enquanto está neste modo. Isso fornece uma execução de produção real que você pode inspecionar, não uma simulada.
Sobre a pergunta 2 — erros aleatórios de expressão após publicar:
Isso quase sempre é o contexto de item se quebrando em algum lugar a montante. Quando um workflow roda ao vivo, cada node vê apenas os itens passados para ele do parent direto — se você tem uma branch ou um node que retorna uma forma diferente do que você testou, expressões que funcionavam em modo manual começam a lançar erros. A solução é adicionar um node “Set” (Edit Fields) logo antes de qualquer node que use expressões de antes na chain, remapeando explicitamente os campos que você precisa. Dessa forma a forma dos dados é sempre explícita e não depende do que aconteceu de estar selecionado no editor quando você testou.
Ei, só uma atualização antes de passar isso para produção, o problema ainda persiste. O nó Merge não funcionou, e tentei algumas formas diferentes de passar dados binários através do nó Code, mas ainda não consegui fazê-lo funcionar corretamente. Obrigado pela ajuda mesmo assim!
Código de correspondência:
const jsonData = $("Multi-track splitter").all();
const videoFiles = $input.all();
let matchedItems = [];
const normalize = (str) => str ? str.toLowerCase().replace(/[^a-z0-9]/g, '') : '';
for (const item of jsonData) {
const song = item.json;
const safeSongName = normalize(song.song_name);
const match = videoFiles.find(v => {
const fileName = v.json.fileName || '';
const cleanFileName = fileName.replace('.mp4', '').replace(/_\d+$/, '');
const safeFileName = normalize(cleanFileName);
return safeFileName.includes(safeSongName) || safeSongName.includes(safeFileName);
});
if (match) {
matchedItems.push({
json: {
...song,
yt_description: `Artist: ${song.artist_name}\n\nAlbum: ${song.album_name}\n\nRelease Date: ${song.release_date}\n\n${song.company_name}\n${song.publisher_name}\n\nNOT auto-generated by YouTube.`,
yt_title: `${song.artist_name} - ${song.song_name}`
},
binary: match.binary
});
}
}
return matchedItems;