{"record":{"id":"eec3bb933cbe0023","repo":"Zie619/n8n-workflows","slug":"quote-not-found","errorCode":null,"errorMessage":"Quote not found","messagePattern":"Quote not found","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"workflows/Code/1864_Code_Executecommand_Create_Webhook.json","lineNumber":434,"sourceCode":"        \"options\": {\n          \"append\": false\n        },\n        \"fileName\": \"music1.mp3\",\n        \"operation\": \"write\"\n      },\n      \"typeVersion\": 1,\n      \"notes\": \"This readWriteFile node performs automated tasks as part of the workflow.\"\n    },\n    {\n      \"id\": \"9fdca64e-79d7-4a58-91dc-4aa9f9b3c4cc\",\n      \"name\": \"Prepare Overlay Text (Quote & Author)\",\n      \"type\": \"n8n-nodes-base.code\",\n      \"position\": [\n        1620,\n        20\n      ],\n      \"parameters\": {\n        \"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\"\n      },\n      \"typeVersion\": 2,\n      \"notes\": \"This code node performs automated tasks as part of the workflow.\"\n    },\n    {\n      \"id\": \"082cf794-89a9-42cc-b9ee-96792a17893f\",\n      \"name\": \"Generate Final Video Clip\",\n      \"type\": \"n8n-nodes-base.executeCommand\",\n      \"position\": [\n        1640,\n        340\n      ],\n      \"parameters\": {\n        \"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\"\n      },\n      \"typeVersion\": 1,\n      \"notes\": \"This executeCommand node performs automated tasks as part of the workflow.\"\n    },","sourceCodeStart":416,"sourceCodeEnd":452,"githubUrl":"https://github.com/Zie619/n8n-workflows/blob/94007c1445d9258a7da116646b79473e7c7c3282/workflows/Code/1864_Code_Executecommand_Create_Webhook.json#L416-L452","documentation":"Thrown by the 'Prepare Overlay Text (Quote & Author)' Code node that builds an FFmpeg drawtext filter. It reads the quote text from the 'Merge File Selection Data' node via $node[...] and fails when json['Qoute'] is falsy. The misspelled key 'Qoute' is the actual field name used throughout this workflow, so a 'correctly' spelled Quote field will also trigger this error.","triggerScenarios":"$node['Merge File Selection Data'].json has no 'Qoute' key, or its value is empty string/null/undefined. Causes: the merge node didn't receive quote items (see error 49), the field is spelled 'Quote' in the data, or the value is blank in the source sheet. Note $node[...] returns the node's first output item only — if the quote sat on a later item, it is invisible here.","commonSituations":"Upstream quote source empty or filtered out; someone 'fixed' the Qoute typo upstream but not in this reader; the merge node emitted the quote on a non-first item; blank cell in the quotes spreadsheet.","solutions":["Confirm the upstream 'Merge File Selection Data' node output actually contains a first item with a non-empty 'Qoute' field (exact spelling).","If the typo was corrected upstream, update this reader (and the selection node in error 49) to 'Quote' consistently.","Use $('Merge File Selection Data').first().json instead of the legacy $node accessor for predictable item resolution, or read from the current item if the data flows in via connections.","Validate the quote branch earlier (at selection time) so the run fails with error 49's clearer message before FFmpeg setup begins."],"exampleFix":"// before\nconst transcript = $node[\"Merge File Selection Data\"].json[\"Qoute\"];\nif (!transcript) {\n  throw new Error(\"Quote not found\");\n}\n\n// after\nconst merged = $('Merge File Selection Data').first().json;\nconst transcript = (merged[\"Qoute\"] ?? merged[\"Quote\"] ?? '').toString().trim();\nif (!transcript) {\n  throw new Error(`Quote not found. Merge node payload keys: ${Object.keys(merged).join(', ')}`);\n}","handlingStrategy":"type-guard","validationCode":"const merged = $('Merge File Selection Data').first().json;\nconst transcript = (merged[\"Qoute\"] ?? merged[\"Quote\"] ?? '').toString().trim();\nconst ready = transcript.length > 0;","typeGuard":"function hasQuote(merged) {\n  return Boolean((merged?.[\"Qoute\"] ?? merged?.[\"Quote\"] ?? '').toString().trim());\n}","tryCatchPattern":null,"preventionTips":["Use $('NodeName').first().json rather than legacy $node access for predictable item resolution.","Accept both spellings (Qoute/Quote) during any typo-migration period.","Validate quote presence at the selection node (error 49) before FFmpeg work starts.","Include the available keys in the error message for instant field-name debugging."],"tags":["n8n","ffmpeg","field-name","typo","code-node"],"backgroundTag":null,"analyzedSha":"94007c1445d9258a7da116646b79473e7c7c3282","analyzedAt":"2026-08-15T04:10:37.591Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}