Zie619/n8n-workflows · critical · Error

Missing binary data

Error message

Missing binary data

What it means

Thrown by 'Validate webhook signature' when $('Webhook to call for Slack command').first() has no binary property. Slack signature verification needs the RAW request body: the n8n Webhook node only stores the raw body as binary (default property 'data') when its 'Raw Body' option (rawBody: true, or 'Include Raw Body' in the UI) is enabled. Without it, item.binary is undefined and this guard fires before any HMAC check runs.

Solutions

  1. Open the 'Webhook to call for Slack command' node and enable Raw Body (set rawBody: true); retest with a real Slack request.
  2. Confirm the binary property name is 'data' (default) or adjust the destructuring to the configured property name.
  3. Guard with a clear message: if (!item.binary || !item.binary.data) throw new Error('Raw body missing: enable the Raw Body option on the webhook node.');
  4. Verify with console.log(Object.keys(item.binary || {})) once working, then remove.

Example fix

// before
const item = $('Webhook to call for Slack command').first();
if (!item.binary) {
  throw new Error('Missing binary data');
}
const { binary: { data } } = item;

// after
const item = $('Webhook to call for Slack command').first();
if (!item.binary || !item.binary.data) {
  throw new Error('Missing binary data: enable the "Raw Body" option on the webhook node so the raw Slack payload is stored as binary.');
}
const { binary: { data } } = item;
Defensive patterns

Strategy: validation

Validate before calling

const item = $('Webhook to call for Slack command').first();
if (!item.binary || !item.binary.data) {
  throw new Error('Missing binary data: enable the Raw Body option on the webhook node — Slack signature verification requires the exact raw payload.');
}

Type guard

const hasRawBody = (item) =>
  item?.binary?.data != null && typeof item.binary.data.data === 'string';

Try / catch

try {
  verifySlackSignature(item, SIGNING_SECRET);
} catch (e) {
  // signature failures should be surfaced, never swallowed — this is a security control
  throw new Error(`Slack signature verification failed: ${e.message}`);
}

Prevention

When it happens

Trigger: Webhook node created without the raw-body option so Slack POSTs arrive with only parsed json (no binary.data), the binary property renamed, or a test invocation (e.g., from the editor 'test' URL with a manually crafted item) that never had binary. Also fires if an intermediate node stripped binary data.

Common situations: Recreating the webhook node and forgetting to tick 'Raw Body' (the single most common cause), n8n version upgrades resetting node options, or copying this verification code into a workflow whose webhook lacks the option.

Related errors


AI-assisted analysis of Zie619/n8n-workflows@94007c1445 (2026-08-15). Data as JSON: /api/errors/b6c1929ffa33ed41. Report an issue: GitHub.

Appendix: source

Thrown at workflows/Webhook/0453_Webhook_Code_Create_Webhook.json:861

        560,
        280
      ],
      "parameters": {
        "jsCode": "const text = $input.first().json.command_text;\nconst parts = text.split(' ');\n\n\n// GET COMMAND\n// for example /cloudbot info mutasem\n// should return \"info\"\nconst command = parts[0];\n\n\n// GET FLAGS \n// for example /cloudbot info mutasem --test --flag\n// should return ['--test', '--flag']\nconst flags = parts.filter((part) => part.startsWith('--'));\n\n\n// GET PARAMS\n// for example /cloudbot info mutasem test\n// should return [\"mutasem\", \"test\"]\nlet params = parts\n  .filter((part, i) => i > 0 && !part.startsWith('--'));\nparams = params.filter((param, i) => {\n  if (param === '-e') {\n    return false;\n  }\n  if (params[i - 1] === '-e') {\n    return false;\n  }\n\n  return true;\n});\n\n\n// GET ENV VARS\n// for example /cloudbot info mutasem -e env=prod\n// should return {env: \"prod\"}\nconst env = parts.filter((val, i) => {\n  return i > 0 && parts[i - 1] === '-e';\n})\n  .reduce((accu, opt) => {\n  if (!opt.includes('=')) {\n    return accu;\n  }\n\n  const key = opt.split('=')[0];\n  const val = opt.split('=')[1];\n  \n  accu[key] = clean(val);\n  return accu;\n}, {});\n\n// Add workflow to run\nconst commands = $input.first().json.commands;\nlet workflow;\nif (commands[command]) {\n  workflow = commands[command];\n}\n\nreturn {\n  ...$input.first().json,\n  command,\n  flags,\n  env,\n  params,\n  workflow,\n}\n\nfunction clean(str) {\n  return str.replaceAll(`‘`, '\\'').replaceAll('“', '\"').replaceAll('”', '\"').replaceAll('’', '\\'');\n}"
      },
      "typeVersion": 1,
      "notes": "This code node performs automated tasks as part of the workflow."
    },
    {
      "id": "22b8502c-dec3-4456-9947-639761517881",
      "name": "Validate webhook signature",
      "type": "n8n-nodes-base.code",
      "position": [
        100,
        280
      ],
      "parameters": {
        "jsCode": "const SIGNING_SECRET = $input.first().json.slack_secret_signature;\nconst item = $('Webhook to call for Slack command').first();\n\nif (!item.binary) {\n  throw new Error('Missing binary data');\n}\n\nconst crypto = require('crypto');\nconst { binary: { data } } = item;\n\nif (\n  !item.json.headers['x-slack-request-timestamp'] ||\n  Math.abs(\n    Math.floor(new Date().getTime() / 1000) -\n      +item.json.headers['x-slack-request-timestamp']\n  ) > 300\n) {\n  throw new Error('Unauthorized, request not fresh');\n}\n\nconst rawBody = Buffer.from(data.data, 'base64').toString()\n\n// compute the basestring\nconst baseStr = `v0:${item.json.headers['x-slack-request-timestamp']}:${rawBody}`;\n\n// extract the received signature from the request headers\nconst receivedSignature = item.json.headers['x-slack-signature'];\n\nconst expectedSignature = `v0=${crypto.createHmac('sha256', SIGNING_SECRET)\n.update(baseStr, 'utf8')\n.digest('hex')}`;\n\n// match the two signatures\nif (expectedSignature !== receivedSignature) {\nthrow new Error('Unauthorized, umatched signatures');\n}\n\nreturn $input.all();"
      },
      "typeVersion": 2,
      "notes": "This code node performs automated tasks as part of the workflow."
    }
  ],
  "pinData": {},
  "connections": {
    "ee413d6c-dad3-4e57-b08d-ffd0f84c682e": {
      "main": [
        [
          {
            "node": "error-handler-ee413d6c-dad3-4e57-b08d-ffd0f84c682e",
            "type": "main",
            "index": 0
          }
        ],
        [
          {

View on GitHub (pinned to 94007c1445)