n8n-io/n8n · error · NodeOperationError
Failed to retrieve download URL for file ${fileId}
Error message
Failed to retrieve download URL for file ${fileId} What it means
Thrown by getVideoDownloadUrl when GET /files/retrieve returns a response whose response.file.download_url is missing. After polling confirms Success and yields a file_id, this second call fetches the signed download URL; absence of download_url means the node cannot retrieve the rendered video bytes.
Source
Thrown at packages/@n8n/nodes-langchain/nodes/vendors/MiniMax/transport/index.ts:98
}
throw new NodeOperationError(
this.getNode(),
`Video task ${taskId} did not complete within the maximum polling time. You can query the task manually using the task ID.`,
);
}
export async function getVideoDownloadUrl(
this: IExecuteFunctions,
fileId: string,
): Promise<string> {
const response = await apiRequest.call(this, 'GET', '/files/retrieve', {
qs: { file_id: fileId },
});
const downloadUrl = response?.file?.download_url as string;
if (!downloadUrl) {
throw new NodeOperationError(
this.getNode(),
`Failed to retrieve download URL for file ${fileId}`,
);
}
return downloadUrl;
}
View on GitHub (pinned to 5ac6606e81)
Solutions
- Retry GET /files/retrieve?file_id=<id> after a short delay to let the file materialize.
- Log the full response to confirm download_url is absent vs. relocated.
- If the file_id is old, resubmit the video generation — the file may have been garbage-collected.
- Verify the credentials base URL is the official MiniMax endpoint.
Defensive patterns
Strategy: retry
Validate before calling
// No caller-side input prevents an upstream missing-download_url response.
// Validate only that the fileId you pass is a non-empty string.
function validateFileId(fileId: unknown): string | null {
if (typeof fileId !== 'string' || fileId.length === 0) return 'fileId must be a non-empty string';
return null;
} Type guard
function hasDownloadUrl(r: unknown): r is { file: { download_url: string } } {
const url = (r as { file?: { download_url?: unknown } })?.file?.download_url;
return typeof url === 'string' && url.length > 0;
} Try / catch
async function getDownloadUrlWithRetry(apiRequest: any, fileId: string, maxAttempts = 3): Promise<string> {
for (let attempt = 0; attempt < maxAttempts; attempt++) {
const response = await apiRequest.call(this, 'GET', '/files/retrieve', { qs: { file_id: fileId } });
const url = response?.file?.download_url as string | undefined;
if (url) return url;
await sleep(2000 * (attempt + 1)); // let the file materialize
}
throw new NodeOperationError(this.getNode(), `Failed to retrieve download URL for file ${fileId}`);
} Prevention
- Retry /files/retrieve a few times after Success — the file may still be materializing.
- Retrieve the download URL promptly after polling to avoid file TTL/garbage-collection.
- Log the full response to distinguish a real API field rename from a race.
- Use the official MiniMax base URL to avoid proxies stripping the download_url field.
When it happens
Trigger: File not yet materialized in MiniMax's storage when /files/retrieve was called (race after Success); file TTL expired between job completion and retrieval call; permission/quota issue preventing download URL minting; API revision moving download_url to a different field; proxy stripping the field.
Common situations: Tight race between Success and file availability; long delay between poll completion and retrieval (file GC'd); account download permission revoked; non-official base URL filtering the response.
Related errors
- No task_id returned from video generation request
- No task_id returned from video generation request
- Video generation succeeded but no file_id was returned
- No audio data returned
- No images were generated
AI-assisted analysis of n8n-io/n8n@5ac6606e81 (2026-08-12).
Data as JSON: /api/errors/c608d5f7b34f24a5.
Report an issue: GitHub.