Zie619/n8n-workflows · error · Error

Author not found

Error message

Author not found

What it means

Same 'Prepare Overlay Text' node as error 50, second guard: the Author field read from $node['Merge File Selection Data'].json is falsy. The quote may have been found, but the attribution line for the FFmpeg overlay is missing, so the node refuses to build a half-labeled video.

Source

Thrown at workflows/Code/1864_Code_Executecommand_Create_Webhook.json:434

        "options": {
          "append": false
        },
        "fileName": "music1.mp3",
        "operation": "write"
      },
      "typeVersion": 1,
      "notes": "This readWriteFile node performs automated tasks as part of the workflow."
    },
    {
      "id": "9fdca64e-79d7-4a58-91dc-4aa9f9b3c4cc",
      "name": "Prepare Overlay Text (Quote & Author)",
      "type": "n8n-nodes-base.code",
      "position": [
        1620,
        20
      ],
      "parameters": {
        "jsCode": "// Define separate configuration for the quote and the author\nconst quoteFont = \"Kanit-Italic.ttf\";      // Font for the quote\nconst quoteFontSize = 70;\nconst authorFont = \"Kanit-Italic.ttf\";         // Font for the author (ensure this supports Thai)\nconst authorFontSize = 50;\nconst fontColor = \"white\";\nconst lineHeightMultiplier = 1.1;\nconst videoWidth = 1080;\nconst margin = 40;  // Gap from left and right edges\n\n// Effective width for the quote text (accounting for left/right margins)\nconst effectiveVideoWidth = videoWidth - 2 * margin;\n\n// Estimate average character width based on quoteFontSize (this is a rough estimate)\nconst avgCharWidth = quoteFontSize * 0.6;\nconst maxCharsPerLine = Math.floor(effectiveVideoWidth / avgCharWidth);\n\n// Retrieve the quote transcript and author from the \"Merge\" node\nconst transcript = $node[\"Merge File Selection Data\"].json[\"Qoute\"];\nif (!transcript) {\n  throw new Error(\"Quote not found\");\n}\nconst author = $node[\"Merge File Selection Data\"].json[\"Author\"];\nif (!author) {\n  throw new Error(\"Author not found\");\n}\n\n// Split the transcript into words and group them into lines based on maxCharsPerLine\nconst words = transcript.split(' ');\nconst lines = [];\nlet currentLine = \"\";\nlet currentCharCount = 0;\n\nwords.forEach(word => {\n  const wordLength = word.length;\n  const additionalSpace = currentLine ? 1 : 0;\n  const potentialLength = currentCharCount + additionalSpace + wordLength;\n  if (potentialLength <= maxCharsPerLine) {\n    currentLine += (currentLine ? \" \" : \"\") + word;\n    currentCharCount = potentialLength;\n  } else {\n    lines.push(currentLine);\n    currentLine = word;\n    currentCharCount = wordLength;\n  }\n});\nif (currentLine) {\n  lines.push(currentLine);\n}\n\n// Calculate layout for the quote block\nconst lineHeight = quoteFontSize * lineHeightMultiplier;\nconst totalHeight = lines.length * lineHeight;\n\n// Build drawtext commands for each quote line (centered horizontally)\n// Each line is positioned so that the entire quote block is vertically centered.\nconst quoteCommands = lines.map((line, index) => {\n  // Escape any single quotes in the line\n  const escapedLine = line.replace(/'/g, \"\\\\'\");\n  return `drawtext=fontfile=${quoteFont}:text='${escapedLine}':fontsize=${quoteFontSize}:fontcolor=${fontColor}:x=(w-text_w)/2:y=((h-${totalHeight})/2)+(${index}*${lineHeight})`;\n});\n\n// Build the drawtext command for the author\n// Place the author text below the quote block with a small gap (e.g. 20 pixels)\n// Align it to the right by setting x = w - text_w - margin.\nconst authorY = `((h-${totalHeight})/2)+(${lines.length}*${lineHeight})+20`;\nconst escapedAuthor = author.replace(/'/g, \"\\\\'\");\nconst authorCommand = `drawtext=fontfile=${authorFont}:text='${escapedAuthor}':fontsize=${authorFontSize}:fontcolor=${fontColor}:x=w-text_w-${margin}:y=${authorY}`;\n\n// Combine all commands (separated by commas) into one drawtext filter string.\nconst fullDrawTextFilter = quoteCommands.concat(authorCommand).join(\", \");\n\n// Return the prepared filter string for insertion into your FFmpeg command.\nreturn {\n  json: {\n    drawText: fullDrawTextFilter\n  }\n};\n"
      },
      "typeVersion": 2,
      "notes": "This code node performs automated tasks as part of the workflow."
    },
    {
      "id": "082cf794-89a9-42cc-b9ee-96792a17893f",
      "name": "Generate Final Video Clip",
      "type": "n8n-nodes-base.executeCommand",
      "position": [
        1640,
        340
      ],
      "parameters": {
        "command": "=ffmpeg -i {{ $('Save Video Background Locally').item.json.fileName }} -i {{ $('Save Music Background Locally').item.json.fileName }} -filter_complex \"[0:v]scale=1080:1920:force_original_aspect_ratio=increase,crop=1080:1920[vid]; color=black@0.3:size=1080x1920:d=10[bg]; [vid][bg]overlay=shortest=1[bgvid]; [bgvid]{{ $json.drawText }}[outv]; [1:a]volume=0.8[aout]\" -map \"[outv]\" -map \"[aout]\" -aspect 9:16 -c:v libx264 -c:a aac -shortest output.mp4 -y"
      },
      "typeVersion": 1,
      "notes": "This executeCommand node performs automated tasks as part of the workflow."
    },

View on GitHub (pinned to 94007c1445)

Solutions

  1. Fill in the Author value in the quote source, or make the source always emit a default like 'Unknown'.
  2. If anonymous quotes are acceptable, default the author instead of throwing: const author = raw || 'Unknown';
  3. Verify the field name/casing in the merge node output matches 'Author' exactly.
  4. Validate both Qoute and Author at the selection stage (error 49's node) so failures surface before FFmpeg rendering.

Example fix

// before
const author = $node["Merge File Selection Data"].json["Author"];
if (!author) {
  throw new Error("Author not found");
}

// after (allow anonymous quotes with a fallback label)
const merged = $('Merge File Selection Data').first().json;
const author = (merged["Author"] ?? '').toString().trim() || 'Unknown';
Defensive patterns

Strategy: fallback

Validate before calling

const merged = $('Merge File Selection Data').first().json;
const author = (merged["Author"] ?? '').toString().trim() || 'Unknown'; // anonymous quotes allowed

Type guard

function resolveAuthor(merged) {
  const a = (merged?.["Author"] ?? merged?.["author"] ?? '').toString().trim();
  return a.length ? a : null; // null = anonymous
}

Prevention

When it happens

Trigger: The merged quote item has no Author key, or Author is empty string/null. Typical when the quotes source stores quotes without attribution (anonymous quotes), the Author column is blank in the sheet, or the field name drifted ('author', 'Author Name').

Common situations: Quotes spreadsheet with optional author column left blank; source API returning quotes without attribution; field renamed upstream.

Related errors


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