Skip to content

Commit dc07d3b

Browse files
committed
added more error handling for ffmpeg
1 parent 59bc411 commit dc07d3b

2 files changed

Lines changed: 119 additions & 84 deletions

File tree

nodes/Robolly/ffmpegMethods.ts

Lines changed: 89 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,81 @@ import fs from 'fs';
33
import { IBinaryData, IExecuteFunctions, NodeApiError, NodeOperationError } from 'n8n-workflow';
44
import { createTempFile } from './utils';
55

6+
function analyzeFFmpegError(stderr: string, code: number): { isFormatError: boolean; userMessage?: string } {
7+
const errorText = stderr.toLowerCase();
8+
9+
if (errorText.includes('requested output format') && errorText.includes('is not known')) {
10+
const formatMatch = stderr.match(/requested output format '([^']+)' is not known/i);
11+
const format = formatMatch ? formatMatch[1] : 'unknown';
12+
return {
13+
isFormatError: true,
14+
userMessage: `Output format '${format}' is not supported by your FFmpeg installation. This could be due to missing codecs or your FFmpeg version not including support for this format. Please check your FFmpeg installation and ensure it includes the necessary encoders/muxers.`
15+
};
16+
}
17+
18+
if (errorText.includes('unknown encoder') || errorText.includes('encoder not found')) {
19+
const encoderMatch = stderr.match(/unknown encoder '([^']+)'/i) || stderr.match(/encoder '([^']+)' not found/i);
20+
const encoder = encoderMatch ? encoderMatch[1] : 'unknown';
21+
return {
22+
isFormatError: true,
23+
userMessage: `Video/audio encoder '${encoder}' is not available in your FFmpeg installation. Your FFmpeg may have been compiled without this codec. Please install a version that includes the '${encoder}' encoder.`
24+
};
25+
}
26+
27+
if (errorText.includes('error initializing the muxer')) {
28+
return {
29+
isFormatError: true,
30+
userMessage: `FFmpeg failed to initialize the output format. This usually indicates the output format is not supported or the file extension doesn't match the requested format. Please verify your FFmpeg installation includes the necessary muxers.`
31+
};
32+
}
33+
34+
if (errorText.includes('unknown decoder') || errorText.includes('decoder not found')) {
35+
const decoderMatch = stderr.match(/unknown decoder '([^']+)'/i) || stderr.match(/decoder '([^']+)' not found/i);
36+
const decoder = decoderMatch ? decoderMatch[1] : 'unknown';
37+
return {
38+
isFormatError: true,
39+
userMessage: `Video/audio decoder '${decoder}' is not available in your FFmpeg installation. Your FFmpeg may have been compiled without this codec. Please install a version that includes the '${decoder}' decoder.`
40+
};
41+
}
42+
43+
if (errorText.includes('incompatible pixel format') || errorText.includes('unsupported pixel format')) {
44+
return {
45+
isFormatError: true,
46+
userMessage: `The pixel format is not supported by the selected codec. This is usually a codec compatibility issue with your FFmpeg installation.`
47+
};
48+
}
49+
50+
if (errorText.includes('no such filter') || errorText.includes('unknown filter')) {
51+
const filterMatch = stderr.match(/no such filter: '([^']+)'/i) || stderr.match(/unknown filter '([^']+)'/i);
52+
const filter = filterMatch ? filterMatch[1] : 'unknown';
53+
return {
54+
isFormatError: true,
55+
userMessage: `Video filter '${filter}' is not available in your FFmpeg installation. Please ensure you have a complete FFmpeg installation with filter support.`
56+
};
57+
}
58+
59+
return { isFormatError: false };
60+
}
61+
62+
function handleFFmpegError(error: any, node: any): never {
63+
if (error.message === 'FFMPEG_NOT_FOUND') {
64+
throw new NodeOperationError(
65+
node,
66+
'FFmpeg is not installed on this system. Please install FFmpeg to use video conversion features. Installation guide: https://ffmpeg.org/download.html'
67+
);
68+
}
69+
70+
if (error.message.includes('is not supported by your FFmpeg installation') ||
71+
error.message.includes('is not available in your FFmpeg installation') ||
72+
error.message.includes('failed to initialize the output format') ||
73+
error.message.includes('is not supported by the selected codec') ||
74+
error.message.includes('is not available in your FFmpeg installation')) {
75+
throw new NodeOperationError(node, error.message);
76+
}
77+
78+
throw new NodeApiError(node, error as any);
79+
}
80+
681
export async function checkFFmpegAvailability(): Promise<void> {
782
return new Promise((resolve, reject) => {
883
const ffmpeg = spawn('ffmpeg', ['-version'], { stdio: ['pipe', 'pipe', 'pipe'] });
@@ -61,7 +136,13 @@ export async function execFFmpeg(args: string[]): Promise<void> {
61136
if (code === 0) {
62137
resolve();
63138
} else {
64-
reject(new Error(`FFmpeg process exited with code ${code}: ${stderr}`));
139+
const exitCode = code || 1;
140+
const errorInfo = analyzeFFmpegError(stderr, exitCode);
141+
if (errorInfo.isFormatError) {
142+
reject(new Error(`FFmpeg process exited with code ${exitCode}: ${errorInfo.userMessage}`));
143+
} else {
144+
reject(new Error(`FFmpeg process exited with code ${exitCode}: ${stderr}`));
145+
}
65146
}
66147
});
67148

@@ -162,13 +243,7 @@ export async function mp4ToGifWithCompression(this: IExecuteFunctions, videoBuff
162243
await cleanupPalette();
163244
await cleanupOutput();
164245

165-
if (error.message === 'FFMPEG_NOT_FOUND') {
166-
throw new NodeOperationError(
167-
this.getNode(),
168-
'FFmpeg is not installed on this system. Please install FFmpeg to use video conversion features. Installation guide: https://ffmpeg.org/download.html'
169-
);
170-
}
171-
throw new NodeApiError(this.getNode(), error as any);
246+
handleFFmpegError(error, this.getNode());
172247
}
173248
}
174249

@@ -220,13 +295,7 @@ export async function mp4ToWebPWithCompression(this: IExecuteFunctions, videoBuf
220295
await cleanupInput();
221296
await cleanupOutput();
222297

223-
if (error.message === 'FFMPEG_NOT_FOUND') {
224-
throw new NodeOperationError(
225-
this.getNode(),
226-
'FFmpeg is not installed on this system. Please install FFmpeg to use video conversion features. Installation guide: https://ffmpeg.org/download.html'
227-
);
228-
}
229-
throw new NodeApiError(this.getNode(), error as any);
298+
handleFFmpegError(error, this.getNode());
230299
}
231300
}
232301

@@ -276,13 +345,7 @@ export async function mp4ToAV1WithCompression(this: IExecuteFunctions, videoBuff
276345
await cleanupInput();
277346
await cleanupOutput();
278347

279-
if (error.message === 'FFMPEG_NOT_FOUND') {
280-
throw new NodeOperationError(
281-
this.getNode(),
282-
'FFmpeg is not installed on this system. Please install FFmpeg to use video conversion features. Installation guide: https://ffmpeg.org/download.html'
283-
);
284-
}
285-
throw new NodeApiError(this.getNode(), error as any);
348+
handleFFmpegError(error, this.getNode());
286349
}
287350
}
288351

@@ -331,13 +394,7 @@ export async function mp4ToHEVCWithCompression(this: IExecuteFunctions, videoBuf
331394
await cleanupInput();
332395
await cleanupOutput();
333396

334-
if (error.message === 'FFMPEG_NOT_FOUND') {
335-
throw new NodeOperationError(
336-
this.getNode(),
337-
'FFmpeg is not installed on this system. Please install FFmpeg to use video conversion features. Installation guide: https://ffmpeg.org/download.html'
338-
);
339-
}
340-
throw new NodeApiError(this.getNode(), error as any);
397+
handleFFmpegError(error, this.getNode());
341398
}
342399
}
343400

@@ -387,13 +444,7 @@ export async function mp4ToVP9WithCompression(this: IExecuteFunctions, videoBuff
387444
await cleanupInput();
388445
await cleanupOutput();
389446

390-
if (error.message === 'FFMPEG_NOT_FOUND') {
391-
throw new NodeOperationError(
392-
this.getNode(),
393-
'FFmpeg is not installed on this system. Please install FFmpeg to use video conversion features. Installation guide: https://ffmpeg.org/download.html'
394-
);
395-
}
396-
throw new NodeApiError(this.getNode(), error as any);
447+
handleFFmpegError(error, this.getNode());
397448
}
398449
}
399450

@@ -442,13 +493,7 @@ export async function mp4ToH264WithCompression(this: IExecuteFunctions, videoBuf
442493
await cleanupInput();
443494
await cleanupOutput();
444495

445-
if (error.message === 'FFMPEG_NOT_FOUND') {
446-
throw new NodeOperationError(
447-
this.getNode(),
448-
'FFmpeg is not installed on this system. Please install FFmpeg to use video conversion features. Installation guide: https://ffmpeg.org/download.html'
449-
);
450-
}
451-
throw new NodeApiError(this.getNode(), error as any);
496+
handleFFmpegError(error, this.getNode());
452497
}
453498
}
454499

@@ -499,12 +544,6 @@ export async function mp4ToWebMWithCompression(this: IExecuteFunctions, videoBuf
499544
await cleanupInput();
500545
await cleanupOutput();
501546

502-
if (error.message === 'FFMPEG_NOT_FOUND') {
503-
throw new NodeOperationError(
504-
this.getNode(),
505-
'FFmpeg is not installed on this system. Please install FFmpeg to use video conversion features. Installation guide: https://ffmpeg.org/download.html'
506-
);
507-
}
508-
throw new NodeApiError(this.getNode(), error as any);
547+
handleFFmpegError(error, this.getNode());
509548
}
510549
}

nodes/Robolly/sharpMethods.ts

Lines changed: 30 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,32 @@ import { IBinaryData, IExecuteFunctions, NodeApiError, NodeOperationError } from
33
import { createTempFile } from './utils';
44
import { checkFFmpegAvailability, checkFFprobeAvailability, execFFmpeg, execFFprobeWithOutput } from './ffmpegMethods';
55

6+
function handleFFmpegImageError(error: any, node: any): never {
7+
if (error.message === 'FFMPEG_NOT_FOUND') {
8+
throw new NodeOperationError(
9+
node,
10+
'FFmpeg is not installed on this system. Please install FFmpeg to use image conversion features. Installation guide: https://ffmpeg.org/download.html'
11+
);
12+
}
13+
14+
if (error.message === 'FFPROBE_NOT_FOUND') {
15+
throw new NodeOperationError(
16+
node,
17+
'FFprobe is not installed on this system. Please install FFmpeg (which includes FFprobe) to use image conversion features. Installation guide: https://ffmpeg.org/download.html'
18+
);
19+
}
20+
21+
if (error.message.includes('is not supported by your FFmpeg installation') ||
22+
error.message.includes('is not available in your FFmpeg installation') ||
23+
error.message.includes('failed to initialize the output format') ||
24+
error.message.includes('is not supported by the selected codec') ||
25+
error.message.includes('is not available in your FFmpeg installation')) {
26+
throw new NodeOperationError(node, error.message);
27+
}
28+
29+
throw new NodeApiError(node, error as any);
30+
}
31+
632
export async function imageToWebP(this: IExecuteFunctions, imageBuffer: Buffer, url: string, extentionOutput: string): Promise<{ binaryData: IBinaryData; responseData: any }> {
733
const { path: tmpInputPath, cleanup: cleanupInput } = await createTempFile('.tmp');
834
const { path: tmpOutputPath, cleanup: cleanupOutput } = await createTempFile('.webp');
@@ -43,13 +69,7 @@ export async function imageToWebP(this: IExecuteFunctions, imageBuffer: Buffer,
4369
await cleanupInput();
4470
await cleanupOutput();
4571

46-
if (error.message === 'FFMPEG_NOT_FOUND') {
47-
throw new NodeOperationError(
48-
this.getNode(),
49-
'FFmpeg is not installed on this system. Please install FFmpeg to use image conversion features. Installation guide: https://ffmpeg.org/download.html'
50-
);
51-
}
52-
throw new NodeApiError(this.getNode(), error as any);
72+
handleFFmpegImageError(error, this.getNode());
5373
}
5474
}
5575

@@ -93,13 +113,7 @@ export async function imageToAVIF(this: IExecuteFunctions, imageBuffer: Buffer,
93113
await cleanupInput();
94114
await cleanupOutput();
95115

96-
if (error.message === 'FFMPEG_NOT_FOUND') {
97-
throw new NodeOperationError(
98-
this.getNode(),
99-
'FFmpeg is not installed on this system. Please install FFmpeg to use image conversion features. Installation guide: https://ffmpeg.org/download.html'
100-
);
101-
}
102-
throw new NodeApiError(this.getNode(), error as any);
116+
handleFFmpegImageError(error, this.getNode());
103117
}
104118
}
105119

@@ -143,13 +157,7 @@ export async function imageToTIFF(this: IExecuteFunctions, imageBuffer: Buffer,
143157
await cleanupInput();
144158
await cleanupOutput();
145159

146-
if (error.message === 'FFMPEG_NOT_FOUND') {
147-
throw new NodeOperationError(
148-
this.getNode(),
149-
'FFmpeg is not installed on this system. Please install FFmpeg to use image conversion features. Installation guide: https://ffmpeg.org/download.html'
150-
);
151-
}
152-
throw new NodeApiError(this.getNode(), error as any);
160+
handleFFmpegImageError(error, this.getNode());
153161
}
154162
}
155163

@@ -208,18 +216,6 @@ export async function imageToRaw(this: IExecuteFunctions, imageBuffer: Buffer, u
208216
await cleanupInput();
209217
await cleanupOutput();
210218

211-
if (error.message === 'FFMPEG_NOT_FOUND') {
212-
throw new NodeOperationError(
213-
this.getNode(),
214-
'FFmpeg is not installed on this system. Please install FFmpeg to use image conversion features. Installation guide: https://ffmpeg.org/download.html'
215-
);
216-
}
217-
if (error.message === 'FFPROBE_NOT_FOUND') {
218-
throw new NodeOperationError(
219-
this.getNode(),
220-
'FFprobe is not installed on this system. Please install FFmpeg (which includes FFprobe) to use image conversion features. Installation guide: https://ffmpeg.org/download.html'
221-
);
222-
}
223-
throw new NodeApiError(this.getNode(), error as any);
219+
handleFFmpegImageError(error, this.getNode());
224220
}
225221
}

0 commit comments

Comments
 (0)