{"record":{"id":"2590fbac6bc61c5b","repo":"mastra-ai/mastra","slug":"only-textnode-is-allowed-for-summary-extractor","errorCode":null,"errorMessage":"Only `TextNode` is allowed for `Summary` extractor","messagePattern":"Only `TextNode` is allowed for `Summary` extractor","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"packages/rag/src/document/extractors/summary.ts","lineNumber":103,"sourceCode":"      const result = await miniAgent.generateLegacy([{ role: 'user', content: prompt }]);\n      summary = result.text;\n    }\n\n    if (!summary) {\n      console.warn('Summary extraction LLM output returned empty');\n      return '';\n    }\n\n    return summary.replace(STRIP_REGEX, '');\n  }\n\n  /**\n   * Extract summaries from a list of nodes.\n   * @param {BaseNode[]} nodes Nodes to extract summaries from.\n   * @returns {Promise<ExtractSummary[]>} Summaries extracted from the nodes.\n   */\n  async extract(nodes: BaseNode[]): Promise<ExtractSummary[]> {\n    if (!nodes.every(n => n instanceof TextNode)) throw new Error('Only `TextNode` is allowed for `Summary` extractor');\n\n    const nodeSummaries = await Promise.all(nodes.map(node => this.generateNodeSummary(node)));\n\n    const metadataList: ExtractSummary[] = nodes.map(() => ({}));\n\n    for (let i = 0; i < nodes.length; i++) {\n      if (i > 0 && this.prevSummary && nodeSummaries[i - 1]) {\n        metadataList[i]!['prevSectionSummary'] = nodeSummaries[i - 1];\n      }\n      if (i < nodes.length - 1 && this.nextSummary && nodeSummaries[i + 1]) {\n        metadataList[i]!['nextSectionSummary'] = nodeSummaries[i + 1];\n      }\n      if (this.selfSummary && nodeSummaries[i]) {\n        metadataList[i]!['sectionSummary'] = nodeSummaries[i];\n      }\n    }\n\n    return metadataList;","sourceCodeStart":85,"sourceCodeEnd":121,"githubUrl":"https://github.com/mastra-ai/mastra/blob/75dd419e613fe9c39f846ffc500716141b74fda6/packages/rag/src/document/extractors/summary.ts#L85-L121","documentation":"SummaryExtractor.extract() requires every node in the input array to be an instance of TextNode. Summary generation works on text content, so other node types (or plain objects mimicking nodes) are rejected before any LLM call.","triggerScenarios":"extract(nodes) where nodes mixes TextNode with other BaseNode subclasses (e.g. ImageDocument/ImageNode) or contains objects deserialized as plain JSON without the TextNode prototype.","commonSituations":"Running extractors over a heterogeneous node list produced by a splitter that emits multiple node types, or passing nodes restored from JSON storage that lost their class identity (no Object.setPrototypeOf / not revived via TextNode.fromJSON).","solutions":["Filter the input: nodes.filter(n => n instanceof TextNode) before calling extract.","If nodes came from JSON, revive them with the proper class (e.g. new TextNode(...)/TextNode.fromJSON) so instanceof passes.","Split the pipeline so only text-bearing nodes go to the SummaryExtractor."],"exampleFix":"// before\nawait extractor.extract(allNodes);\n// after\nawait extractor.extract(allNodes.filter(n => n instanceof TextNode));","handlingStrategy":"type-guard","validationCode":"const textNodes = nodes.filter((n): n is TextNode => n instanceof TextNode);\nif (textNodes.length === 0) return [];","typeGuard":"const isTextNode = (n: BaseNode): n is TextNode => n instanceof TextNode;","tryCatchPattern":"try {\n  return await extractor.extract(nodes);\n} catch (e) {\n  if (e instanceof Error && e.message.includes('Only `TextNode` is allowed')) {\n    return extractor.extract(nodes.filter(isTextNode));\n  }\n  throw e;\n}","preventionTips":["Always narrow node arrays with instanceof TextNode before summary extraction.","Revise JSON-persisted nodes through their class constructors so instanceof works.","Keep extraction pipelines type-homogeneous per stage."],"tags":["type-error","rag","node-types"],"backgroundTag":"wrong-node-type","analyzedSha":"75dd419e613fe9c39f846ffc500716141b74fda6","analyzedAt":"2026-08-30T00:15:31.844Z","schemaVersion":2},"datasetVersion":"2026-08-30T03:17:51.788Z"}