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
- Fill in the Author value in the quote source, or make the source always emit a default like 'Unknown'.
- If anonymous quotes are acceptable, default the author instead of throwing: const author = raw || 'Unknown';
- Verify the field name/casing in the merge node output matches 'Author' exactly.
- 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
- Decide explicitly whether Author is required; if optional, substitute 'Unknown' instead of throwing.
- Default the Author column in the source sheet for anonymous entries.
- Keep field names consistent between source, merge, and this reader.
- Surface missing-author data as a warning in logs while still rendering the video.
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
- Quote not found
- Quote not found
- Approved quantity must be greater than 0
- ${fileName} → ${baseName} → Unrecognized file name structure
- The video ID parameter is empty.
AI-assisted analysis of Zie619/n8n-workflows@94007c1445 (2026-08-15).
Data as JSON: /api/errors/036dfcd2ff4d7596.
Report an issue: GitHub.