n8n-io/n8n · error · NodeOperationError

The file content is not in JSONL format

Error message

The file content is not in JSONL format

What it means

When uploading a fine-tuning file via the v2 OpenAI node, the API returns a 'Bad request' error with description 'Expected file to have JSONL format' if the file is not valid JSONL. The catch block detects this pattern and rethrows as a NodeOperationError with a user-friendly description. This is identical logic to the v1 file upload (error 890), duplicated across node versions.

Source

Thrown at packages/@n8n/nodes-langchain/nodes/vendors/OpenAi/v2/actions/file/upload.operation.ts:101

	try {
		const response = await apiRequest.call(this, 'POST', '/files', {
			option: { formData },
			headers: formData.getHeaders(),
		});

		return [
			{
				json: response,
				pairedItem: { item: i },
			},
		];
	} catch (error) {
		if (
			error.message.includes('Bad request') &&
			error.description?.includes('Expected file to have JSONL format')
		) {
			throw new NodeOperationError(this.getNode(), 'The file content is not in JSONL format', {
				description:
					'Fine-tuning accepts only files in JSONL format, where every line is a valid JSON dictionary',
			});
		}
		throw error;
	}
}

View on GitHub (pinned to 5ac6606e81)

Solutions

  1. Convert the file to JSONL format — one JSON object per line, no array wrapper
  2. Validate each line is valid JSON: run cat file.jsonl | python -m json.tool --json-lines to check
  3. Ensure correct binary property name is selected in the node
  4. If building the file programmatically, use JSON.stringify per line followed by newline

Example fix

// before — [{"prompt": "...", "completion": "..."}]\n (JSON array)
// after  — {"prompt": "...", "completion": "..."}\n{"prompt": "...", "completion": "..."}\n (JSONL)
Defensive patterns

Strategy: validation

Validate before calling

// Validate JSONL format before uploading
function validateJsonl(content: string): boolean {
  const lines = content.trim().split('\n').filter(l => l.trim());
  return lines.length > 0 && lines.every(line => {
    try { JSON.parse(line); return true; } catch { return false; }
  });
}
if (!validateJsonl(fileContent)) {
  throw new UserError('File is not valid JSONL. Each line must be a valid JSON object.');
}

Type guard

function isJsonlContent(content: string): boolean {
  if (!content.includes('\n')) return false;
  return content.trim().split('\n').every(line => {
    try { JSON.parse(line); return true; } catch { return false; }
  });
}

Try / catch

try {
  await uploadFile(this, i);
} catch (error) {
  if (error instanceof NodeOperationError && error.message.includes('JSONL')) {
    const converted = convertToJsonl(fileContent);
    await uploadJsonlString(this, i, converted);
  }
  throw error;
}

Prevention

When it happens

Trigger: A file uploaded with purpose 'fine-tune' is not in JSONL format. The OpenAI API validates server-side and returns a 400. The catch block pattern-matches on error.message containing 'Bad request' and error.description containing 'Expected file to have JSONL format'.

Common situations: Uploading a .json array file instead of .jsonl; uploading CSV or plain text for fine-tuning; malformed JSONL with invalid JSON lines; wrong file selected via binary input.

Related errors


AI-assisted analysis of n8n-io/n8n@5ac6606e81 (2026-08-12). Data as JSON: /api/errors/6cd2a4d8a00ae62d. Report an issue: GitHub.