Known Limitations
What's not ready yet — transparency about current platform limitations
Written By Philippe
Last updated 3 days ago
Known Limitations
Transparency matters. Here is what works, what does not, and what to expect.
Is It a Fit?
The short version, before you read the detail below. Everything in the right-hand column is spelled out in the sections that follow.
Node-Specific Limitations
These nodes are supported but have specific constraints:
Code & Function Nodes
- JavaScript only — Python is not supported. Switch the Code node language to JavaScript
async/awaitand Promises work — write code the way you would in n8n. Because there is no network and no timers, a promise can only be resolved by your own code; awaiting something that never resolves stops the run with a clear message instead of hanging- No timers —
setTimeoutandsetIntervalare unavailable. Use the Wait node to delay a run - No network access — cannot make HTTP calls from code. Use an HTTP Request node, which also handles auth, retries and rate limits
- No server-side modules —
requireandimportare unavailable, so packages cannot be loaded.BufferandTextEncoder/TextDecoderare available URL,URLSearchParamsandstructuredCloneare not available — build query strings with string methods, and copy an object withJSON.parse(JSON.stringify(value))- Unavailable names are refused at upload — a Code node that calls
setTimeout,setInterval,URL,URLSearchParams,structuredClone,fetch,require,process.env,$env,$secrets,$getWorkflowStaticData,$evaluateExpression,$fromAI,$tool,$getPairedItem,$execution.customData,Intl.RelativeTimeFormator acrypto.subtlekey function is refused when you upload, with a message naming the alternative. The same names raise the same message at run time, so nothing fails as an undefined variable. If you see a bare "is not defined", it is a typo in your code, not a platform limit - Random and hashing work; signing does not —
crypto.randomUUID()andcrypto.getRandomValues()are available, andcrypto.subtle.digest()supports SHA-256 and SHA-1.sign,verify,encrypt,decryptand key derivation are refused at upload: they need key material, which the platform never exposes to a Code node. Let the API you call do the signing. The Crypto node is unsupported for the same reason console.logproduces no output — it does not raise an error, the output is silently discarded. Return the value instead to see it- Secure code sandbox CPU limit (5 seconds to 5 minutes) — Heavy computation has its own compute limit, from a 5-second floor up to 5 minutes depending on the workflow's price per run. The limit is for the whole run: all Code steps in a run share it. Waiting on APIs, LLMs, or webhooks does not count against it. This limit is time spent running code inside the secure code sandbox; since code there has no network or timers to wait on, awaiting cannot idle against the limit. Network waits in HTTP Request, LLM, and database nodes use the workflow execution limits below instead
$getWorkflowStaticDatais not available — a workflow that calls it is refused at upload. It previously returned an empty object and silently discarded whatever you wrote to it, which reset between items, so nothing written to it ever survived. Cross-run persistence is intentionally unsupported: n8n stores this as global mutable state on the workflow record, which races under concurrent runs and does not scale. Use$('NodeName')to pass data between nodes, and an HTTP Request node to read and write an external store for state that must outlive a run$envis not available — n8n denies it by default, and so do we. A workflow that reads$envin a Code node or an expression is refused at upload. Use$varsfor values you set on the workflow
Wait Node
- Maximum wait: 5 minutes — the same limit as a full workflow run. Publishing a workflow with a longer wait is rejected. A "specific time" wait whose target is further away stops the run with a clear error
- Webhook and form resume not supported — workflows using
resume: webhookorresume: formare rejected when publishing; useTime IntervalorSpecific Timeinstead - A wait holds the run open for its duration. For longer pauses, split work across separate runs with a Schedule Trigger
Webhook Node
- Multiple webhook triggers supported — each gets its own URL
- Supported methods: GET, POST, PUT, PATCH, DELETE, HEAD
- Auth options: Basic Auth, Header Auth, JWT Auth (passphrase or public key). The secret is a credential saved in your Secure Vault, never a value in the workflow
- Some request headers are not available —
authorization,cookie,x-forwarded-for,cf-connecting-ip,x-real-ip,x-ph-distinct-id,payment-signatureandsign-in-with-xare removed before the workflow sees the request, and so is the header a Header Auth credential checks. A workflow that reads one of them literally from the Webhook node's output ($json.headers.cookiein the next node,$('Webhook').item.json.headers['authorization']anywhere) is refused at upload. Have the caller send the value in a custom header such asx-caller-token, or in a query parameter - The webhook address is assigned when the workflow is turned on — an HTTP Request node that calls the workflow's own Webhook node by its n8n path (
…/webhook/<path>or…/webhook-test/<path>) is refused at upload, because that address does not exist here. Read the URL from a$varsvalue instead: set a placeholder before turn-on, then replace it with the address the dashboard shows - Respond Immediately answers when the run ends — the caller gets the same answer as in n8n (
{"message":"Workflow was started"}, your Response Data text, or no body), but only after the workflow finishes. A failed run gets the same answer, not an error. To return the workflow's output, set Respond to When Last Node Finishes - Streaming response mode not supported — refused at upload. Set Respond to Immediately, When Last Node Finishes, or Using Respond to Webhook Node
- Only Run If not supported — refused at upload, because every request would run the workflow. Remove the option and check the condition with an If node after the Webhook
- Allow Multiple HTTP Methods: only the first output runs — every request runs the first output, whatever its method. A workflow with a second output connected is refused at upload. With only the first output connected, a request for any other listed method also runs the first output, where n8n would run nothing after the Webhook. Turn the option off and choose one HTTP Method when that matters
- JWT Auth claims are not added to the output — the Webhook node does not output
jwtPayload. Upload refuses$json.jwtPayloadin a node directly after a JWT Auth Webhook, and$('<that webhook>')reads ofjwtPayload(.json,.item.json,.first().json,.last().json). Other reads pass upload and give an empty value. Have the caller send the claims you need in the body or a custom header
Respond to Webhook Node
- Put Response in Field is one flat key —
a.bgives a field nameda.b, not a nestedathenb - A binary file's type replaces your
Content-Typeheader — set the type on the file instead - JWT Token response not supported — refused at upload. Respond with JSON or Text instead
- Response output branch not supported — the second output does not carry the response sent. A workflow that connects it is refused at upload. Disconnect it, or turn off Enable Response Output Branch
HTTP Request Node
- Bearer and Basic Auth via Secure Vault — Digest and custom auth not supported. OAuth2 is supported via Secure Vault for major services (Google, Microsoft, and others). Custom OAuth scopes and the Test Connection button are not available. Use dedicated integration nodes for OAuth services
- Generic credential Header Auth and Query Auth not supported — when using a Generic Credential Type, the Header Auth and Query Auth options are blocked. Use a Predefined Credential Type instead (e.g., Google Gemini, Slack)
- In-memory binary support — base64-encoded, ~50MB limit per file. No streaming by ID
- 10-second default timeout per request
GraphQL Node
- Header Auth and Query Auth not supported — use Bearer Auth or Basic Auth instead
Merge Node
- combineBySql mode NOT supported — use other merge modes (append, combineByFields, combineByPosition, combineAll)
Item Lists Node
- Sort by Code NOT functional — use simple sort or the dedicated Sort node with a field-based sort instead
- Other operations work: concatenate, limit, summarize, split out items
Sort Node
- Sort by Code not supported — use Sort by Field (simple) or Random instead. Code-based sort requires a Node.js task runner that is not available on the platform
Convert to File Node
- Spreadsheet and document formats not supported — the following output formats require libraries not available on the platform:
- CSV, HTML, XLSX, XLS, ODS, RTF
- Use Move Base64 to File, Convert to JSON, or Convert to Text File as alternatives
Extract from File Node
- Binary document formats not supported — the following extraction formats are not available:
- PDF, XLSX, XLS, ODS, ICS (iCal), HTML table, RTF
- Supported formats: JSON, Text, XML, CSV (plain text), Base64
Remove Duplicates Node
- In-execution dedup only — the following operations require persistent database storage and are not supported:
- Remove Items Seen in Previous Executions
- Remove Items Up To Stored Incremental Key
- Remove Items Up To Stored Date
- Clear Deduplication History
- Use the in-execution dedup mode (removes duplicates within the current run)
Firebase Cloud Firestore Node
- Service Account auth not supported — use OAuth2 via Secure Vault instead
Discord Node
- V2 only — V1 not supported
- Webhook connection type not supported — use Bot Token or OAuth2. A Discord webhook URL is itself the secret, so Secure Vault cannot protect it (see Webhook-URL credentials)
- In-memory binary — file attachments supported via base64 (~50MB limit)
Google Chat Node
- Incoming webhooks not supported — the webhook URL carries its own credentials in the address. Use the Message resource with OAuth2 or Service Account auth (see Webhook-URL credentials)
Telegram Node
- In-memory binary support — direct file/binary uploads via base64 (~50MB limit)
- Can send images/videos via URL or binary
Send and Wait (Multiple Nodes)
The "Send and Wait" operation pauses a workflow until a human responds. Supported with:
- Response Type: Approval (buttons) — Free Text and Custom Form are not supported
- Owner-funded workflows only — the response window is billed to the workflow owner
- Each response is billed as its own run — the work before the message is one run, and the work after the response is another. A workflow that asks for several approvals bills once per approval, so fund it for the number of responses a run can request, not for one
- 7-day response window — after that the approval link expires; the workflow run up to the message stays recorded
- One extra confirmation click — selecting Approve or Decline opens a page with a confirm button, and nothing is recorded until that button is pressed. This is deliberate: mail systems and chat apps fetch links automatically to build previews, and without the confirmation step one of those fetches would answer on your behalf.
- Turn off "Limit Wait Time" — the response window is always 7 days. A workflow that sets a shorter limit is rejected when you publish it.
- Responding from inside Microsoft Teams or Skype — those apps open links in a built-in window that cannot be told apart from their automatic link preview, so a response cannot be recorded there. The page says so and asks you to reopen the address in a browser; the approval is untouched and still works. Every other app, and email, responds normally.
- Only the person you send the link to can respond — the link carries its own permission, so treat it like a password. Anyone it is forwarded to can answer in your place, and it can only be answered once.
- Not supported: Free Text and Custom Form response types, "Dispatch and Wait" on the GitHub node, and Send and Wait inside a sub-workflow.
- The message carries no "sent automatically by n8n" footer unless you turn on the Append n8n Attribution option.
What the person responding sees: the message arrives with Approve and Decline buttons. Selecting one opens a confirmation page; selecting the button there records the response and shows "Got it, thanks". If the link was already answered, has expired, was cancelled by the workflow owner, or the workflow has run out of budget, the page explains which and records nothing.
What the workflow owner sees: the workflow's Executions tab lists outstanding responses under "Waiting for response", with the expiry date. The list never shows the link itself. Cancelling a pending response is available through the API, not yet in the dashboard.
Available on: Slack, Discord, Telegram, Gmail, WhatsApp, Google Chat, Microsoft Teams, Microsoft Outlook.
YouTube Node
- Video upload not supported — resumable video upload requires streams, which are not available. Use Get, Get All, Update, or Rate operations instead
Chat Trigger Node
- Hosted chat mode not supported — use Embedded Chat mode (
mode=webhook) and embed your own chat client - Basic Auth and n8n User Auth not supported — set authentication to
noneand place auth in front of the workflow URL - "Make Available in n8n Chat Hub" not supported — this option has no effect on the platform
OpenAI Node
- Text and chat completions only
- Not supported: image generation (DALL-E), audio (TTS), assistants API, file operations
Output Parser Structured
- $ref in JSON schemas not supported — may produce incorrect types
- Use inline schema definitions instead of references
Memory Buffer Window
- 1-week activity TTL — conversation memory auto-expires after 1 week of inactivity
- Memory is scoped per workflow instance and session
Agent Node
- V2 and V3 supported — V1 (SQL Agent, Conversational, ReAct, Plan and Execute) requires database access and is not available
Summarization Chain
- JSON input only — binary input mode (
nodeInputBinary) is not supported. Use JSON input or connect a Document Loader
MCP Client Tool / MCP Client Node
- SSE transport not supported — switch to HTTP Streamable transport instead
Default Data Loader
- JSON data type only — binary document loading (PDF, DOCX, etc.) is not supported. Use JSON data type to load text from previous nodes
Credential Limitations
Not Available
These credential features from n8n are not available on indie.money:
- SSL certificate bypass — The platform enforces SSL validation for all connections. Services with self-signed certificates (some self-hosted instances) cannot skip SSL checks. Affected services: ERPNext, Gotify, Grafana, Grist, Mattermost, WordPress, Zammad
- Custom OAuth scopes — OAuth permissions are configured at the platform level with all common scopes included by default. You cannot customize scopes per connection. LinkedIn includes organization posting scopes automatically. Microsoft Teams includes channel message reading. Discord, Linear, and Webflow use API Key authentication which has full access
- Connection testing — The "Test Connection" button from n8n is not yet available. If your credentials are invalid, you will see an error when the workflow first tries to use them
Webhook-URL credentials
Some integrations authenticate with a webhook URL — a single address that doubles as the password, because anyone holding it can post as you. Discord webhooks and Google Chat incoming webhooks both work this way.
Secure Vault protects a credential by keeping the secret and attaching it to each outgoing request, so the secret never travels inside your workflow. That requires the secret and the destination address to be separate values. A webhook URL is both at once, so supporting it would mean storing the secret in the workflow in readable form — where anyone who can view the workflow could copy it and post to your channel.
Workflows using one of these connection types are rejected when you publish, with a message naming the node. Use a connection type that keeps the secret separate from the address:
Service-Specific Credential Limitations
Production-Only OAuth Services
These OAuth services connect to their production environment only. Sandbox/test environments are not configurable through OAuth:
- QuickBooks (Production only)
- Salesforce (Production only)
Self-Hosted Services
Most services with self-hosted options show an environment selector (Cloud / Self-Hosted) that reveals a URL field for your instance. If you do not see this option for a service you self-host, contact support.
Platform Limits
- 5-minute run limit — total elapsed time from start to end, including all time spent waiting on network responses. Every workflow stops at 5 minutes
- A separate compute limit covers heavy computation only, and is set by the workflow's price per run — see the secure code sandbox limit above. Waiting on APIs, AI models or databases counts toward the 5-minute run limit and not toward the compute limit
- 50 MB file size limit — files downloaded or uploaded by nodes must be under 50 MB each. See File Handling & Size Limits for details
- Time zone conversion in nodes covers 1970 to 2050 — a node that converts a date to a named time zone (Date & Time version 1, Google Calendar, Box, Slack, Notion, Zoom, ClickUp, Clockify, Asana and others) stops with an error for a date outside that range. UTC, expressions and the Code node convert any date
- 2 MB execution result JSON limit — per-execution result JSON stored to platform storage is capped at 2 MB (enforced at the platform storage level)
Nodes Not Yet Available
- Database nodes (Postgres, MySQL, Redis, MongoDB) — on the roadmap
- Email nodes (Send Email, IMAP) — requires secure proxy infrastructure
- Some vector stores and embeddings (Supabase, Pinecone, Qdrant, OpenAI, Ollama) are supported. Others are not available.
- Document loaders (binary mode) — JSON mode is available, but binary document loading (PDF, DOCX, EPUB) requires file system access
Expression Engine
- Most standard n8n expressions work, with modern JavaScript: classes, iterators,
Symbol,WeakMap,SetandMap asyncfunctions andawaitare refused at upload — an expression returns its value at once, so a promise would never settlesetIntervalis refused in expressions. Use the Wait node to repeat work on a schedule- An expression has a memory budget of 16 MB, a recursion depth of about 680 calls, and a processing budget. A loop that never ends, one that fills memory, or a recursion that goes too deep stops with an error on that node
- A result keeps only plain data. These values change when the expression returns them:
undefinedand an empty slot in an array come back asnull({{ [1, undefined] }}gives[1, null]), and aSetorMapcomes back as{}. Use them inside the expression and return an array or an object.NaN,Infinity,-Infinityand-0stay as they are, as in n8n - Spreading a string into an object gives an empty object:
{{ {...'ab'} }}gives{}, not{"0": "a", "1": "b"}
What We Are Working On
Check the roadmap to see what is planned and vote on what you need most. High-demand features get built first.
Found Something Else?
Use the messaging widget in the bottom corner to report issues. Include what you tried, what happened, and what you expected.
Related
Was this helpful?
More in Platform Reference
Advanced Technical DetailsService Composition (Workflow-to-Workflow Calls)Technical Architecture OverviewFile Handling & Size LimitsStill need help? Ask the team