{"record":{"id":"b708bc599acfb7fd","repo":"n8n-io/n8n","slug":"turn-errorreason-message","errorCode":null,"errorMessage":"${turn.errorReason.message}","messagePattern":"\\$\\{turn\\.errorReason\\.message\\}","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/@n8n/agents/src/runtime/loop/agent-runtime.ts","lineNumber":923,"sourceCode":"\t\t\t// Fold the just-finished turn's usage in before the abort check so a\n\t\t\t// stop that lands right after the model call still bills its tokens.\n\t\t\ttotalUsage = mergeUsage(totalUsage, turn.usage);\n\t\t\tincrementTokenCountFromUsage(options?.executionCounter, turn.usage);\n\t\t\tsink.reportUsage(totalUsage);\n\n\t\t\tthis.assertNotAborted(abortScope);\n\n\t\t\tlastFinishReason = turn.finishReason;\n\t\t\tlist.addResponse(turn.newMessages);\n\t\t\t// The turn is now in the list; drop any retained streamed text so a later\n\t\t\t// abort's snapshot can't duplicate it (a stop before this point recovers it).\n\t\t\tsink.onTurnFolded?.();\n\n\t\t\tif (turn.aiFinishReason !== 'tool-calls') {\n\t\t\t\t// A rejected/filtered request (e.g. a provider prompt safety block)\n\t\t\t\t// surfaces as an output-less turn instead of an SDK error — throw so\n\t\t\t\t// the failure reaches the caller rather than ending the run silently.\n\t\t\t\tif (turn.errorReason) throw new Error(turn.errorReason.message);\n\t\t\t\tstructuredOutput = turn.structuredOutput;\n\t\t\t\tthis.emitTurnEnd(turn.newMessages, extractSettledToolCalls(turn.newMessages));\n\t\t\t\treachedStopCondition = true;\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tconst batch = await this.toolExecutor.iterateToolCallsConcurrent({\n\t\t\t\t...buildToolBatchContext(toolMap),\n\t\t\t\ttoolCalls: turn.toolCalls,\n\t\t\t});\n\t\t\tconst finalized = await finishToolBatch(batch, toolMap, iterationCount + 1);\n\t\t\tif (finalized.suspended) return finalized.result;\n\n\t\t\t// Emit TurnEnd after all tool calls in this iteration are processed\n\t\t\tthis.emitTurnEnd(turn.newMessages, extractSettledToolCalls(list.responseDelta()));\n\n\t\t\t// Step boundary reached with nothing pending: durably checkpoint so a\n\t\t\t// crash before the next model call loses only the in-flight step.","sourceCodeStart":905,"sourceCodeEnd":941,"githubUrl":"https://github.com/n8n-io/n8n/blob/5ac6606e81f67bb9534255570cd4e86fd8101eee/packages/@n8n/agents/src/runtime/loop/agent-runtime.ts#L905-L941","documentation":"Thrown by the Set node validator (v3.3+) when parameters.assignments is a valid object but its inner assignments field is present and is not an array. The inner field must be the list of assignment entries.","triggerScenarios":"params.assignments is a record AND assignments.assignments !== undefined AND !Array.isArray(assignments.assignments) — e.g. it is an object, string, or number.","commonSituations":"Nesting one level too deep (assignments.assignments = {...}); an AI builder mirrors the outer object shape inside; a typo turning the array into an object.","solutions":["Make parameters.assignments.assignments an array of assignment objects.","If the inner list is genuinely empty, use assignments: { assignments: [] }.","Omit the inner assignments key entirely if you only want the outer placeholder (undefined is tolerated)."],"exampleFix":"// before\nset({\n  name: 'Set X',\n  assignments: { assignments: { id: '1', name: 'x', value: 1, type: 'number' } },\n});\n\n// after\nset({\n  name: 'Set X',\n  assignments: {\n    assignments: [{ id: '1', name: 'x', value: 1, type: 'number' }],\n  },\n});","handlingStrategy":"validation","validationCode":"function assertAssignmentsArray(assignments: unknown): void {\n  if (assignments !== undefined && !Array.isArray(assignments)) {\n    throw new Error('parameters.assignments.assignments must be an array');\n  }\n}\n\n// before building:\nassertAssignmentsArray(params.assignments?.assignments);","typeGuard":"function isAssignmentList(v: unknown): v is unknown[] {\n  return Array.isArray(v);\n}","tryCatchPattern":null,"preventionTips":["Use a typed assignment builder that always produces an array for the inner field.","Avoid double-nesting the assignments object.","Omit the inner key rather than passing a non-array."],"tags":["set-node","assignments","parameters","node-version"],"backgroundTag":null,"analyzedSha":"5ac6606e81f67bb9534255570cd4e86fd8101eee","analyzedAt":"2026-08-12T05:26:35.080Z","schemaVersion":2},"datasetVersion":"2026-08-12T13:17:24.610Z"}