{
  "title": "Five inspected error-handling signals in 2,030 representative n8n workflow files",
  "url": "https://noderecipe.com/n8n-error-handling-data",
  "author": "Ali Ilyas",
  "publisher": "NodeRecipe",
  "licence": "CC BY 4.0 — reuse with attribution to https://noderecipe.com/n8n-error-handling-data",
  "analysis_run": "2026-09-12",
  "published": "2026-09-13",
  "last_updated": "2026-10-17",
  "scripts": {
    "repository": "https://github.com/noderecipe52/n8n-error-handling-data",
    "as_run_tag": "published-counts-2026-09",
    "note": "The tag holds the scripts exactly as run on 2026-09-12/13 for these counts. The repository also has an independent re-implementation (27 rows re-derived, 0 mismatches) and the corpus-wide rewrite check."
  },
  "corrections": [
    {"date": "2026-10-17", "note": "Published the analysis scripts and checked every file against the pre-rewrite history (f8639776, 2025-09-28), where we had checked one. Signal counts are unchanged and no file changes on any counted signal. Nodes injected upstream raise corpus_shape.nodes_per_workflow (median 11 before the rewrites) and most of the stopAndError, manualTrigger and noOp counts in corpus_shape.most_common_node_types; see caveats. Existing keys and values are unchanged."},
    {"date": "2026-10-03", "note": "Clarified signal and grouping terminology. Counts and existing metric keys are unchanged for compatibility. Metric names are historical identifiers; use method.metric_definitions for interpretation."},
    {
      "date": "2026-09-29",
      "note": "Renamed the 31/40 subgroup metric to specify the three absent signals. Count, denominator and share are unchanged. The previous wording implied absence of all five signals, which applies to 28/40. Consumers using the old metric names should migrate to the names below.",
      "csv_metric_before": "upsert_wf_automatic_trigger_and_no_error_handling",
      "csv_metric_after": "upsert_wf_non_manual_trigger_no_retry_no_error_output_no_error_trigger",
      "json_path_before": "google_sheets_upsert.of_the_53_workflows.automatic_trigger_and_no_error_handling",
      "json_path_after": "google_sheets_upsert.of_the_53_workflows.non_manual_trigger_no_retry_no_error_output_no_error_trigger"
    }
  ],
  "source": {
    "repository": "Zie619/n8n-workflows",
    "url": "https://github.com/Zie619/n8n-workflows",
    "licence": "MIT",
    "branch": "main",
    "commit": "94007c1445d9258a7da116646b79473e7c7c3282",
    "commit_date": "2026-06-24T14:16:03Z",
    "cloned": "2026-09-12",
    "clone_command": "git clone --depth 1 https://github.com/Zie619/n8n-workflows.git corpus",
    "note": "The repository's last push (2026-06-24) predates our clone (2026-09-12) and no push has occurred since, so 94007c14 is the tree these numbers were computed from. Re-derive with: git ls-remote https://github.com/Zie619/n8n-workflows.git main"
  },
  "method": {
    "denominator": 2030,
    "metric_definitions": {"no_error_handling_field_of_any_kind": "Historical key: none of five predicates are satisfied in the representative file: retryOnFail=true, onError=continueErrorOutput, onError=continueRegularOutput, continueOnFail=true, or node type ending in errorTrigger. This is not absence of all possible handling or every related field.", "suppression_only": "At least one continueRegularOutput or continueOnFail=true declaration, with no inspected retry, error-output or Error Trigger signal. Downstream error checks and runtime failures were not measured.", "suppression_only_errors_silently_swallowed": "CSV alias for suppression_only. The historical name does not establish silent runtime failure."},
    "denominator_note": "2,061 JSON files grouped into 2,030 normalized-content groups; one representative per group is counted. This denominator applies to whole-corpus workflow percentages, not subgroup or node metrics. Fingerprint = SHA-1 over sorted serialized normalized nodes plus connections, with these keys stripped recursively: id, versionId, webhookId, position, createdAt, updatedAt, meta, tags, pinData, active, instanceId. This also strips nested parameter keys and does not establish byte identity or runtime equivalence.",
    "fields_read": ["node properties (retryOnFail, onError, continueOnFail, maxTries, waitBetweenTries, alwaysOutputData)", "unscoped n8n-nodes-base.* node types"],
    "fields_deliberately_not_used": ["connections", "settings", "meta", "scoped @n8n/* node types"],
    "fields_deliberately_not_used_scope": "Excluded from declaration counts and topology inference. Normalized connections still participate in the grouping fingerprint.",
    "subgroup_definitions": {
      "non_manual_trigger_no_retry_no_error_output_no_error_trigger": "Among 40 upsert workflow representatives with a non-manual trigger node, 31 have no node with retryOnFail=true, onError=continueErrorOutput, or a type ending in errorTrigger. continueRegularOutput and legacy continueOnFail=true are not excluded. A non-manual trigger uses the historical rule: type contains rigger or ends in .webhook, and does not contain manualTrigger. This is not a concurrency or execution-behavior test."
    },
    "why": "Three of the five top-level objects in this corpus have been rewritten upstream, and nodes were added. Node properties were first verified unchanged on one workflow across four commits spanning the rewrites (provenance-check.py), then on every file (rewrite-check.py, 2026-10-17): on the 29,363 nodes present both at f8639776 and at the pinned commit, every measured field is unchanged except a credential scrub on two Google Sheets update nodes that no figure reads, and none of the 2,057 files changes on any counted signal. Connections, settings and metadata were rewritten, so no topology claim is made.",
    "tested_against": "n8n 2.33.7"
  },
  "caveats": [
    "These are files people publish and download, not a sample of what runs in production. Nobody has that dataset.",
    "No claim is made about whether an error output is wired to anything. The graph in this corpus is not trustworthy.",
    "errorWorkflow is null in all 2,026 files that carry settings — an injected value, not the authors'. Error Triggers were detected by looking for the node instead.",
    "The grouping fingerprints node names and connections, which the rewrites changed. On the pre-rewrite files (2,057) the same rule gives 1,974 groups, of which 1,670 (84.6%) satisfy none of the five predicates, against 1,721 of 2,030 (84.8%) here. Error Triggers are 18 either way.",
    "corpus_shape includes nodes the rewrites injected (1,223 across 1,124 files, mostly stopAndError and manualTrigger). Among the 2,030 representatives, 1,035 of 1,072 stopAndError and 142 of 906 manualTrigger nodes are injected, and 3,977 of 4,363 noOp nodes had another type before the rewrites. Before the rewrites the median workflow had 11 nodes and the mean was 14.5. Do not cite the node-type counts as authored behaviour."
  ],
  "error_handling": {
    "no_error_handling_field_of_any_kind": { "workflows": 1721, "share_pct": 84.8 },
    "no_retry_no_error_output_no_error_trigger": { "workflows": 1810, "share_pct": 89.2 },
    "on_error_continue_error_output": { "workflows": 121, "share_pct": 6.0 },
    "retry_on_fail_true": { "workflows": 108, "share_pct": 5.3 },
    "on_error_continue_regular_output": { "workflows": 100, "share_pct": 4.9 },
    "suppression_only": { "workflows": 89, "share_pct": 4.4 },
    "continue_on_fail_true_legacy": { "workflows": 43, "share_pct": 2.1 },
    "contains_error_trigger": { "workflows": 18, "share_pct": 0.9 }
  },
  "google_sheets_upsert": {
    "google_sheets_nodes": 595,
    "google_sheets_workflows": 279,
    "operations": { "append": 183, "update": 125, "appendOrUpdate": 70, "upsert": 1, "other": 14, "unset": 202 },
    "append_or_update_or_upsert_nodes": 71,
    "append_or_update_or_upsert_workflows": 53,
    "nodes_specifying_a_matching_column": { "nodes": 69, "of": 71, "share_pct": 97.2 },
    "of_the_53_workflows": {
      "no_retry_no_error_branch_no_error_trigger": { "workflows": 43, "share_pct": 81.1 },
      "retry_on_fail_anywhere": { "workflows": 6, "share_pct": 11.3 },
      "retry_on_fail_on_the_upsert_node": { "workflows": 3, "share_pct": 5.7 },
      "continue_error_output_anywhere": { "workflows": 6, "share_pct": 11.3 },
      "contains_error_trigger": { "workflows": 0, "share_pct": 0.0 },
      "error_suppression_present": { "workflows": 8, "share_pct": 15.1 },
      "automatic_trigger": { "workflows": 40, "share_pct": 75.5 },
      "non_manual_trigger_no_retry_no_error_output_no_error_trigger": { "workflows": 31, "of": 40, "share_pct": 77.5 }
    }
  },
  "corpus_shape": {
    "files": 2061,
    "unique_workflows": 2030,
    "duplicate_groups": 23,
    "redundant_copies": 31,
    "nodes_per_workflow": { "median": 12, "mean": 15.1, "max": 246 },
    "most_common_node_types": {
      "stickyNote": 7041, "noOp": 4363, "set": 2523, "httpRequest": 2122,
      "if": 1084, "stopAndError": 1072, "code": 1005, "manualTrigger": 906, "googleSheets": 595
    },
    "top_triggers": {
      "manualTrigger": 906, "webhook": 349, "scheduleTrigger": 330,
      "executeWorkflowTrigger": 180, "formTrigger": 122
    }
  },
  "cite_as": "Ilyas, A. (2026). n8n Error Handling: What 2,030 Published Workflows Actually Declare. NodeRecipe. https://noderecipe.com/n8n-error-handling-data"
}
