n8n-workflow-linter by Payload
Small software that earns its keep. A free utility by Payload.
A zero-dependency Python CLI that statically lints an exported n8n workflow JSON for production-readiness smells - the small misconfigurations that turn into 3 a.m. pages.
Install
Nothing. Python 3.10+ and this repo.
python3 lint.py workflow.json
Usage
# lint a workflow exported from n8n (Download in the workflow menu)
python3 lint.py my-workflow.json
# machine-readable output
python3 lint.py my-workflow.json --json
# only check for N8N002 and N8N003
python3 lint.py --only N8N002 --only N8N003 my-workflow.json
# do not check for N8N002
python3 lint.py --ignore N8N002 my-workflow.json
# write safe automatic fixes to my-workflow.fixed.json
# the original export is NEVER overwritten
python3 lint.py --fix my-workflow.json
Exit codes: 0 = clean or selected issues fixed, 1 = errors found or a fixed-output conflict, 2 = warnings remaining.
--fix currently removes populated pinData only when N8N009 is selected. It writes
a separate <workflow>.fixed.json next to the source; it never modifies the
original or overwrites an existing fixed output. Review the generated file
before importing it into n8n.
Real output:
$ python3 lint.py my-workflow.json
WARN [N8N002] node 'Call webhook': HTTP Request has no timeout configured
fix: set options.timeout (ms), e.g. 10000, so a hung endpoint cannot stall the workflow
ERROR [N8N004] node 'Authed call': hardcoded secret in parameters.headerParameters.parameters[0].value (Bear...)
fix: move the secret into n8n Credentials and reference it; never commit literal secrets in workflow JSON
1 error(s), 1 warning(s)
Rules
| Code | Severity | What it flags |
|---|---|---|
| N8N001 | warn | Non-trigger node without explicit onError handling |
| N8N002 | warn | HTTP Request node with no options.timeout |
| N8N003 | warn | HTTP Request node with retryOnFail disabled |
| N8N004 | error | Hardcoded credential/secret literal in node parameters (n8n ={{ }} expressions are not flagged) |
| N8N005 | error | Workflow has no trigger node |
| N8N006 | warn | Workflow has multiple trigger nodes |
| N8N007 | warn | Disabled node left in the workflow |
| N8N008 | warn | Node with no connections at all |
| N8N009 | warn | Node with pinned data |
Notes on scope, stated plainly:
- Secret detection is heuristic: it looks for secret-like parameter names
(
password,api_key,secret,token, ...) and credential-style{"name","value"}pairs (e.g. anAuthorizationheader) holding literal values. It is not a substitute for a secrets scanner. - "Trigger" means a node whose type ends in
Trigger, plus theStartandWebhooknode types. Sticky notes are ignored.
Tests
python3 tests/run_tests.py
10 fixtures: one clean workflow plus one workflow per smell. All must pass.
What this doesn't do
This is a static linter, not a reliability system. It doesn't execute your workflow, load-test it, simulate failure modes, add retries and circuit breakers, or give you production-ready workflow templates.
For the full 10-workflow hardening system - failure alerting, timeout circuit breakers, retry policies, and production patterns for AI agent workflows - see the n8n Production AI Agent Reliability Kit ($99) by Payload.
License
MIT - see LICENSE. Copyright 2026 Payload.
Payload - small, sharp tools for developers. Developer portal: https://payloadhq.github.io/ · All products: https://payloadtools.gumroad.com/ · Contact: kylers.partners@gmail.com
More from Payload · payloadhq.github.io · all Payload repos
Related: n8n-reliability-free-samples · n8n-nodes-payload-flow
GitHub Action
Run the linter in CI on every exported workflow in your repo. Pin to a release rather than a moving branch:
- uses: Payloadhq/n8n-workflow-linter@v1.1.0
with:
paths: 'workflows/**/*.json'
Inputs: paths (space-separated glob patterns, default workflows/**/*.json) and fail-on-error (default true).
The action installs the linter from this repository and checks every matched file. Workflows with lint errors fail the job when fail-on-error is true, so a workflow with a hardcoded secret or no trigger cannot merge unnoticed. Warnings are printed in the job log but never fail the job on their own. If no files match, the action passes and says so.
Metadata
Release files for n8n-workflow-linter 1.1.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | Actions |
|---|---|---|---|---|
| n8n_workflow_linter-1.1.0.tar.gz | 8.1 kB | With provenance | Details for n8n_workflow_linter-1.1.0.tar.gz |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Actions Reset |
|---|---|---|---|---|
| n8n_workflow_linter-1.1.0-py3-none-any.whl | Python 3 | none | any | Details for n8n_workflow_linter-1.1.0-py3-none-any.whl |
Total release size: 17.1 kB
Release files / n8n_workflow_linter-1.1.0.tar.gz
| Download URL | n8n_workflow_linter-1.1.0.tar.gz |
|---|---|
| Size | 8.1 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
fca821ebf64e2a942e406e7561180873889eb94c2af662f7e9f1b72d8f7cf66d
|
|
BLAKE2b-256 checksum How to use checksums |
a3951c761db09b89de24e469cfe4f26322256ae092c6bbf215cfcc07e2d7aef3
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.16
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Nov 4, 2026.
Transparency logRelease files / n8n_workflow_linter-1.1.0-py3-none-any.whl
| Download URL | n8n_workflow_linter-1.1.0-py3-none-any.whl |
|---|---|
| Size | 9.0 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
9222277a9652e8cbb0289b0406adb860e8d4c31fbcc40230ef1a218107591b3f
|
|
BLAKE2b-256 checksum How to use checksums |
10acba23eef72fe40966c796a76b77a9af021e9fd0c7e399f9481b097c1de7b0
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.16
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Nov 4, 2026.
Transparency logSecurity for n8n-workflow-linter 1.1.0
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
Full provenance
Both files in this release have been uploaded with provenance metadata.
Attestation for n8n_workflow_linter-1.1.0.tar.gz
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Nov 4, 2026.
Transparency logA note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.