{"record":{"id":"6996256e16db7156","repo":"n8n-io/n8n","slug":"reflector-merge-index-marker-must-be-a-known-o","errorCode":null,"errorMessage":"Reflector merge[${index}].marker must be a known observation marker","messagePattern":"Reflector merge\\[(.+?)\\]\\.marker must be a known observation marker","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/@n8n/agents/src/runtime/memory/observation-log-reflector.ts","lineNumber":323,"sourceCode":"\tif (!isRecord(value)) throw new Error(`Reflector merge[${index}] must be an object`);\n\tconst supersedes = readStringArray(value.supersedes, `merge[${index}].supersedes`);\n\tconst marker = readMarker(value.marker, index);\n\tif (typeof value.text !== 'string') {\n\t\tthrow new Error(`Reflector merge[${index}].text must be a string`);\n\t}\n\n\tconst parentId = readOptionalParentId(value.parentId, index);\n\treturn {\n\t\tsupersedes,\n\t\tmarker,\n\t\ttext: value.text,\n\t\t...(parentId !== undefined && { parentId }),\n\t};\n}\n\nfunction readMarker(value: unknown, index: number): ObservationLogMarker {\n\tif (typeof value !== 'string') {\n\t\tthrow new Error(`Reflector merge[${index}].marker must be a known observation marker`);\n\t}\n\n\tswitch (value.toUpperCase()) {\n\t\tcase 'CRITICAL':\n\t\t\treturn 'critical';\n\t\tcase 'IMPORTANT':\n\t\t\treturn 'important';\n\t\tcase 'INFO':\n\t\t\treturn 'info';\n\t\tcase 'COMPLETION':\n\t\t\treturn 'completion';\n\t\tdefault:\n\t\t\tthrow new Error(`Reflector merge[${index}].marker must be a known observation marker`);\n\t}\n}\n\nfunction readOptionalParentId(value: unknown, index: number): string | null | undefined {\n\tif (value === undefined) return undefined;","sourceCodeStart":305,"sourceCodeEnd":341,"githubUrl":"https://github.com/n8n-io/n8n/blob/5ac6606e81f67bb9534255570cd4e86fd8101eee/packages/@n8n/agents/src/runtime/memory/observation-log-reflector.ts#L305-L341","documentation":"`readMarker` is called for each merge object and first checks that `value.marker` is a string. This throw (line 323) fires when `marker` is not a string at all — it is missing, null, a number, etc. The marker classifies the merged observation's severity. A separate throw at line 336 covers the case where the string is not one of the four known values.","triggerScenarios":"The reflector LLM returns a merge object with `{ \"marker\": null }`, `{ \"marker\": 1 }`, or omits `marker` entirely (so it is `undefined`).","commonSituations":"The reflector prompt does not list `marker` as required. The model used a non-string sentinel. The model omitted the field for merges it considered low priority.","solutions":["Use the `index` from the error to find the merge object whose `marker` is non-string.","Update the reflector prompt: `marker` is required and must be one of `CRITICAL`, `IMPORTANT`, `INFO`, `COMPLETION` (case-insensitive).","If you want `marker` to be optional, patch the reader to default to `'info'` when `marker` is absent — but coordinate with the memory system's expectations.","Enable structured-output / JSON-schema mode to enforce `marker: string` at the API level."],"exampleFix":"// before: { \"merge\": [{ \"supersedes\": [\"obs-1\"], \"marker\": null, \"text\": \"...\" }] }\n// after:  { \"merge\": [{ \"supersedes\": [\"obs-1\"], \"marker\": \"INFO\", \"text\": \"...\" }] }","handlingStrategy":"validation","validationCode":"const raw = JSON.parse(extractJsonObject(output));\nif (Array.isArray(raw.merge)) {\n  for (const m of raw.merge) {\n    if (isRecord(m) && typeof m.marker !== 'string') {\n      m.marker = 'INFO'; // default to info when missing/non-string\n    }\n  }\n}","typeGuard":"function isStringMarker(value: unknown): value is string {\n  return typeof value === 'string';\n}","tryCatchPattern":"try {\n  const reflection = parseObservationLogReflectionJson(output);\n} catch (e) {\n  logger.warn('Reflector marker not a string', { index: 'see message', output });\n}","preventionTips":["Default `marker` to `'INFO'` in a pre-normalization step if you want it optional.","List the four allowed markers prominently in the reflector prompt.","Use structured-output mode with `marker: string` constraint."],"tags":["llm-output-validation","observation-log","json-parsing","required-field","type-mismatch"],"backgroundTag":null,"analyzedSha":"5ac6606e81f67bb9534255570cd4e86fd8101eee","analyzedAt":"2026-08-12T05:26:35.080Z","schemaVersion":2},"datasetVersion":"2026-08-13T19:17:28.613Z"}