Pular para o conteúdo principal
Atualizado em Sep 17, 2026

Executar código

Use esta ação quando um passo precisar de lógica personalizada que o CEL não consegue expressar — reformatar dados, calcular valores, processar arquivos ou chamar uma API com código. Uma única ação cobre as duas linguagens: escolha JavaScript ou Python no campo Linguagem.

Melhor para

  • Transformar JSON de passos anteriores exatamente no formato de que um passo posterior precisa
  • Cálculos, parsing e validações além do que expressões CEL conseguem fazer
  • Pequenas integrações usando fetch (qualquer linguagem) quando a ação Requisição HTTP não for flexível o suficiente
  • Trabalho com documentos e arquivos usando as bibliotecas incluídas do Python — planilhas, PDFs, imagens, DOCX/PPTX

Escolhendo a linguagem

JavaScriptPython
RuntimeSandbox V8 isolado (sem APIs do Node.js)Python 3.12 em um container descartável
Redefetch com proteção SSRFfetch com proteção SSRF (mediado pelo host)
Tempo limite (ms)100–30.000, padrão 5.0001.000–120.000, padrão 30.000
Memória (MB)8–256, padrão 128128–2.048, padrão 512
BibliotecasRecursos padrão do JavaScriptopenpyxl, python-docx, python-pptx, pdfplumber, pypdf, pandas, Pillow, reportlab, markitdown — sem pip em tempo de execução

As duas linguagens compartilham as mesmas entradas e saídas: Dados de entrada estruturados, Arquivos de entrada, um resultado estruturado, arquivos de saída e logs em um formato unificado.

Campos principais

CampoO que faz
Linguagemjavascript (padrão) ou python
CódigoO código a executar. JavaScript é envolvido em uma IIFE assíncrona, então você pode usar await no nível superior e terminar com return <valor>. Python executa como um script comum; escreva o resultado em /work/out/output.json
Dados de entradaExpressão CEL opcional avaliada antes da execução. JavaScript vê o valor na variável input; Python vê na variável INPUT
Arquivos de entradaExpressão CEL opcional que avalia para um array de referências de storage [{bucket, fullPath, name?}] — por exemplo step(0).files ou um input de workflow do tipo arquivo. O conteúdo dos arquivos é entregue ao sandbox; o código nunca acessa o storage diretamente
PropósitoRótulo opcional do que o código faz, exibido nos logs
Tempo limite (ms)Limite de tempo de execução em milissegundos, restrito por linguagem (veja a tabela acima). Código que ultrapassa o limite — incluindo loops infinitos — é encerrado
Limite de memória (MB)Limite de memória do sandbox, restrito por linguagem

Arquivos de entrada e de saída

As duas direções compartilham os mesmos limites: no máximo 10 arquivos, 20 MiB por arquivo, 24 MiB no total. Nomes de arquivo devem começar com letra ou dígito e podem conter letras, dígitos, ., _, - e espaços (até 128 caracteres). Os nomes input.json e output.json são reservados — eles são os canais de dados estruturados.

Lendo arquivos de entrada:

  • JavaScript — files.readText(name) retorna o conteúdo como string de texto (decodificado como UTF-8); files.read(name) retorna como string base64, para dados binários
  • Python — os arquivos aparecem em /work/in/<nome> (somente leitura)

Escrevendo arquivos de saída:

  • JavaScript — files.writeText(name, text, {contentType?}) para texto; files.write(name, contentBase64, {contentType?}) para binário. contentType é inferido da extensão quando omitido
  • Python — escreva os arquivos em /work/out/

Para trabalhar com texto — CSV, JSON, Markdown — use readText / writeText e dispense o base64:

const rows = files.readText("data.csv").split("\n").map((line) => line.split(","));
files.writeText("summary.txt", `${rows.length} linhas`);

O par base64 existe para arquivos binários (imagens, PDFs, planilhas), normalmente para repassar os bytes sem alteração ou entregá-los ao fetch.

Os arquivos de saída são enviados ao storage da sua empresa após a execução e aparecem como referências de storage em step(N).files. Passos posteriores podem encadeá-los — por exemplo, um passo Python cujos Arquivos de entrada sejam step(0).files lê tudo o que o passo de código anterior produziu.

O sandbox JavaScript

O código executa em um sandbox V8 isolado em um serviço de execução separado. Não há acesso a APIs do Node.js (require, process, sistema de arquivos) nem a APIs de navegador — apenas os recursos padrão do JavaScript mais estas pontes:

  • input — o valor avaliado de Dados de entrada (null quando ausente)
  • console.log/info/warn/error — capturados e retornados na saída logs
  • fetch(url, options) — HTTP com proteção SSRF (endereços privados e internos são bloqueados) que retorna {ok, status, statusText, body}, com body interpretado como JSON quando possível e retornado como texto caso contrário. Corpos de resposta são limitados a 10 MiB — uma resposta maior falha a etapa em vez de ser carregada na memória
  • files.read / files.readText / files.write / files.writeText — veja acima
  • atob(base64) / btoa(binaryString) — o codec base64 padrão, para converter os valores com que files.read e files.write trabalham. btoa segue a regra da web de rejeitar caracteres acima de U+00FF, então use files.writeText para texto UTF-8 em vez de btoa

Não existe Buffer, nem TextDecoder/TextEncoder, nem requireatob/btoa e os helpers de texto de files são a forma suportada de converter entre bytes e strings.

O sandbox Python

O código executa como python3 job.py em um container novo que é destruído após a execução:

  • INPUT — o valor avaliado de Dados de entrada, carregado de /work/in/input.json (None quando ausente)
  • fetch(url, method="GET", headers=None, body=None) — o mesmo HTTP com proteção SSRF da linguagem JavaScript, fornecido pela plataforma (o container em si não tem rede bruta; cada requisição é mediada pelo host). Retorna um dict {"ok", "status", "statusText", "body"}, com body interpretado como JSON quando possível e retornado como texto caso contrário; corpos de resposta são limitados a 10 MiB. Levanta FetchError quando a requisição não pode ser feita (um alvo bloqueado ou inacessível). Uma resposta não-2xx não é um erro — ela retorna com ok=False, como na linguagem JavaScript. Não dependa de requests ou urllib para chamadas externas — use fetch()
  • Arquivos de entrada em /work/in/ (somente leitura), arquivos de saída em /work/out/
  • Escreva o resultado estruturado do passo como JSON em /work/out/output.json — é isso que step(N).result recebe. print() vai para a saída logs, não para o resultado. Um job que não escreve output.json recebe step(N).result = null
  • Apenas as bibliotecas incluídas listadas acima são importáveis — não há pip em tempo de execução
  • Apenas um job Python executa por vez; um runner ocupado falha o passo com um erro com retry (veja abaixo)

Buscar dados e transformá-los com as bibliotecas incluídas:

import json
resp = fetch("https://api.example.com/report", headers={"accept": "application/json"})
if not resp["ok"]:
raise FetchError(f"upstream retornou {resp['status']}")
rows = resp["body"]["items"]
with open("/work/out/output.json", "w") as f:
json.dump({"count": len(rows)}, f)

O que passos posteriores podem usar

  • step(N).result — o resultado estruturado (valor do return em JavaScript / output.json em Python), limitado a 2 MiB — escreva dados volumosos como arquivos. null quando o código não retornou nada / não escreveu output.json
  • step(N).files — referências de storage dos arquivos que o código escreveu: [{name, bucket, fullPath, contentType, size}]
  • step(N).logs — saída capturada como entradas [{level, message}] (níveis de console no JavaScript; stdout / stderr no Python), até 200 entradas de 2.000 caracteres cada
  • step(N).executionTimeMs — quanto tempo o código executou

Versões anteriores expunham o valor de retorno do JavaScript como step(N).data. Agora é step(N).result, para as duas linguagens.

Como esta etapa publica result e não data, step_data e step_has_content resolvem dentro de result: step_data(N, "count")step(N).result.count, que normalmente é o que você quer. Os três irmãos na raiz da etapa são invisíveis para eles — leia esses com get(step(N), "files"), e não com step_has_content(N, "files"), que erraria em silêncio enquanto step_ok(N) continua true. Isso vale mesmo quando o código não retornou nada, porque aí result é null. Veja Ações que publicam na raiz da etapa.

Erros

CódigoSignificado
code_execution_failedO código lançou uma exceção — verifique step(N).logs
code_execution_timeoutO código ultrapassou o tempo limite (ambas as linguagens)
code_executor_busyO único slot do runner Python está ocupado — com retry; executar o passo novamente é seguro
code_result_too_largeO resultado serializado passa de 2 MiB — retorne um resumo pequeno e escreva dados volumosos como arquivos
code_result_invalid_jsonPython escreveu /work/out/output.json, mas não é JSON válido
code_input_files_invalidArquivos de entrada não avaliou para referências válidas, ultrapassou os limites ou usou um nome reservado
code_input_file_not_accessibleUm arquivo de entrada não foi encontrado ou não está acessível a partir deste workspace
code_input_file_unavailableFalha transitória de storage ao ler um arquivo de entrada — com retry
python_unavailableA linguagem Python não está habilitada neste ambiente

Dicas

  • Sempre produza um resultado — return no JavaScript, output.json no Python — e mantenha-o compatível com JSON.
  • Use console.log / print() enquanto constrói o passo; a saída logs é a forma mais fácil de depurar.
  • Cada chamada de fetch também é limitada pelo tempo do passo, então mantenha chamadas a terceiros bem dentro do orçamento de tempo.
  • Arquivos são o canal certo para qualquer coisa grande: o resultado é limitado a 2 MiB, enquanto arquivos carregam até 24 MiB por execução.