n8n-io/n8n · error · Error
Reflector field "${fieldName}" must contain only strings
Error message
Reflector field "${fieldName}" must contain only strings What it means
After `readStringArray` confirms a value is an array, it iterates every element and asserts each is a `typeof string`. This throws when the array contains non-string elements (numbers, booleans, nested objects, null). The reflector contract requires every element of `drop` and `merge[i].supersedes` to be a plain string.
Source
Thrown at packages/@n8n/agents/src/runtime/memory/observation-log-reflector.ts:292
if (parentId === undefined || parentId === null) return parentId;
return activeById.has(parentId) && !removedIds.has(parentId) ? parentId : null;
}
function extractJsonObject(output: string): string {
const start = output.indexOf('{');
const end = output.lastIndexOf('}');
if (start === -1 || end === -1 || end < start) {
throw new Error('Reflector output did not contain a JSON object');
}
return output.slice(start, end + 1);
}
function readStringArray(value: unknown, fieldName: string): string[] {
if (!Array.isArray(value)) throw new Error(`Reflector field "${fieldName}" must be an array`);
const strings: string[] = [];
for (const item of value) {
if (typeof item !== 'string') {
throw new Error(`Reflector field "${fieldName}" must contain only strings`);
}
strings.push(item);
}
return strings;
}
function readMergeArray(value: unknown): ObservationLogMerge[] {
if (!Array.isArray(value)) throw new Error('Reflector field "merge" must be an array');
return value.map(readMerge);
}
function readMerge(value: unknown, index: number): ObservationLogMerge {
if (!isRecord(value)) throw new Error(`Reflector merge[${index}] must be an object`);
const supersedes = readStringArray(value.supersedes, `merge[${index}].supersedes`);
const marker = readMarker(value.marker, index);
if (typeof value.text !== 'string') {
throw new Error(`Reflector merge[${index}].text must be a string`);
}View on GitHub (pinned to 5ac6606e81)
Solutions
- Log the raw LLM output and identify which array element is non-string (the error names the field, e.g. `merge[0].supersedes`).
- Fix the reflector prompt to clarify that all IDs are strings and `null` must not appear inside arrays — omit the entry instead.
- If observation IDs in your system are numeric, ensure the reflector input renders them as quoted strings so the model echoes them back as strings.
- Consider enabling strict JSON-schema constrained decoding (structured outputs) on providers that support it so the array element type is enforced at the API level.
Example fix
// before: LLM returns { "drop": [42, "obs-2"] }
// Ensure the rendered observation log the reflector sees uses string IDs:
// [obs-42] some observation text
// so the model echoes "obs-42" not 42.
// after: { "drop": ["obs-42", "obs-2"] } Defensive patterns
Strategy: validation
Validate before calling
function isStringArray(value: unknown): value is string[] {
return Array.isArray(value) && value.every((item) => typeof item === 'string');
}
// Pre-check before parseObservationLogReflectionJson:
const raw = JSON.parse(extractJsonObject(output));
for (const field of ['drop'] as const) {
if (raw[field] !== undefined && !isStringArray(raw[field])) {
throw new Error(`Pre-validation: ${field} contains non-string elements`);
}
} Type guard
function isStringArray(value: unknown): value is string[] {
return Array.isArray(value) && value.every((item) => typeof item === 'string');
} Try / catch
try {
const reflection = parseObservationLogReflectionJson(output);
} catch (e) {
logger.warn('Reflector array element type error', { field: 'see message', output });
// skip reflection cycle
} Prevention
- Render all observation IDs as quoted strings in the reflector input so the LLM echoes strings.
- Use structured-output mode with `string[]` array element constraints.
- Treat reflection failures as non-fatal — wrap in try/catch and continue the run.
When it happens
Trigger: The reflector LLM returns `{ "drop": [123, "obs-2"] }` (mixed number and string) or `{ "merge": [{ "supersedes": [null, "id1"] }] }` (null mixed in).
Common situations: The model confused numeric observation IDs with string IDs. The model emitted `null` placeholders for entries it could not supersede. A schema-drift where the reflector prompt changed the expected ID format.
Related errors
- Reflector merge[${index}] must be an object
- Reflector merge[${index}].marker must be a known observation
- Reflector merge[${index}].parentId must be a string or null
- Reflector field "${fieldName}" must be an array
- Reflector field "merge" must be an array
AI-assisted analysis of n8n-io/n8n@5ac6606e81 (2026-08-12).
Data as JSON: /api/errors/78de8edc494fad09.
Report an issue: GitHub.