n8n-io/n8n · error

Nested ${Array.isArray(value) ? 'array' : 'object'} found at

Error message

Nested ${Array.isArray(value) ? 'array' : 'object'} found at key "${key}". Only flat objects are supported.

What it means

Thrown by parseJson() during the second validation pass (structured-file-parser.ts:353) when any value in a JSON object is itself a non-null object or array. parseStructuredFile only emits flat tabular rows, so nested structures are rejected before column type inference runs. The check is value-based and runs after header collection.

Source

Thrown at packages/@n8n/instance-ai/src/parsers/structured-file-parser.ts:354

			throw new Error('JSON array items must be flat objects (not arrays, nulls, or primitives)');
		}
		const dangerousKey = hasDangerousKey(item as Record<string, unknown>);
		if (dangerousKey) {
			throw new Error(`Dangerous key "${dangerousKey}" found in JSON data`);
		}
		for (const key of Object.keys(item as Record<string, unknown>)) {
			keySet.add(key);
		}
	}

	const rawHeaders = [...keySet];

	// Validate all values are flat
	for (const item of parsed) {
		const obj = item as Record<string, unknown>;
		for (const [key, value] of Object.entries(obj)) {
			if (value !== null && typeof value === 'object') {
				throw new Error(
					`Nested ${Array.isArray(value) ? 'array' : 'object'} found at key "${key}". Only flat objects are supported.`,
				);
			}
		}
	}

	return { rawHeaders, allRows: parsed as Array<Record<string, unknown>> };
}

// ── Main parse function ─────────────────────────────────────────────────────

export function parseStructuredFile(
	attachment: AttachmentInfo,
	attachmentIndex: number,
	input: ParseFileInput,
): ParseFileOutput {
	// Decode base64
	let decoded: Buffer;

View on GitHub (pinned to 5ac6606e81)

Solutions

  1. Flatten nested fields before attaching: convert {"user":{"name":"x"}} to {"user.name":"x"}, and arrays to comma-joined strings or separate rows.
  2. If the data is genuinely hierarchical, do not use parseStructuredFile — preprocess into a tabular projection first.
  3. Validate with a recursive walk that rejects non-primitive values before calling parseStructuredFile.

Example fix

// before: [{ "id": 1, "tags": ["a","b"] }]
// after:  [{ "id": 1, "tags": "a,b" }]
Defensive patterns

Strategy: validation

Validate before calling

function isFlatRecord(v: unknown): v is Record<string, string | number | boolean | null> {
  if (typeof v !== 'object' || v === null || Array.isArray(v)) return false;
  for (const val of Object.values(v)) {
    if (val !== null && typeof val === 'object') return false;
  }
  return true;
}
if (!Array.isArray(parsed) || !parsed.every(isFlatRecord)) {
  throw new Error('Flatten nested fields before attaching');
}

Type guard

function isFlatValue(v: unknown): v is string | number | boolean | null {
  return v === null || typeof v === 'string' || typeof v === 'number' || typeof v === 'boolean';
}

Try / catch

try { return parseStructuredFile(attachment, idx, input); }
catch (e) {
  if (e instanceof Error && e.message.startsWith('Nested ')) {
    // prompt caller to flatten nested fields
  }
  throw e;
}

Prevention

When it happens

Trigger: A JSON array attachment where any object has a value that is an object literal ({...}) or array ([...]), e.g. {"id": 1, "tags": ["a","b"]} or {"user": {"name":"x"}}. Also reached via the xlsx JSON round-trip when a sheet cell is serialized as a nested structure.

Common situations: Sending a denormalized REST response (objects with nested related resources) to a tool expecting tabular rows; LLM-generated eval-data with array fields; a sheet whose merged/formula cells serialize to objects via SheetJS.

Related errors


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