mastra-ai/mastra · error
Source object must be a single RelatedNodeInfo object
Error message
Source object must be a single RelatedNodeInfo object
What it means
The BaseNode.sourceNode getter reads the SOURCE relationship and expects a single RelatedNodeInfo object. If the stored relationship is an array (the shape used for CHILD-style relationships), it throws because a source is by definition one node.
Source
Thrown at packages/rag/src/document/schema/node.ts:33
protected constructor(init?: BaseNodeParams<T>) {
const { id_, metadata, relationships } = init || {};
this.id_ = id_ ?? randomUUID();
this.metadata = metadata ?? ({} as T);
this.relationships = relationships ?? {};
}
abstract get type(): ObjectType;
abstract getContent(): string;
abstract getMetadataStr(): string;
get sourceNode(): RelatedNodeInfo<T> | undefined {
const relationship = this.relationships[NodeRelationship.SOURCE];
if (Array.isArray(relationship)) {
throw new Error('Source object must be a single RelatedNodeInfo object');
}
return relationship;
}
get prevNode(): RelatedNodeInfo<T> | undefined {
const relationship = this.relationships[NodeRelationship.PREVIOUS];
if (Array.isArray(relationship)) {
throw new Error('Previous object must be a single RelatedNodeInfo object');
}
return relationship;
}
get nextNode(): RelatedNodeInfo<T> | undefined {
const relationship = this.relationships[NodeRelationship.NEXT];
View on GitHub (pinned to 75dd419e61)
Solutions
- Assign the SOURCE relationship as a single object: relationships[NodeRelationship.SOURCE] = relatedNodeInfo (not [relatedNodeInfo]).
- If data comes from serialized JSON, normalize arrays to a single object before constructing/using the node.
- Use library constructors/builders to populate relationships rather than mutating the relationships map directly.
Example fix
// before node.relationships[NodeRelationship.SOURCE] = [sourceInfo]; // after node.relationships[NodeRelationship.SOURCE] = sourceInfo;
Defensive patterns
Strategy: type-guard
Validate before calling
const rel = node.relationships[NodeRelationship.SOURCE]; const hasValidSource = rel !== undefined && !Array.isArray(rel);
Type guard
const isSingleRelatedNodeInfo = <T extends NodeRelationship>(v: unknown): v is RelatedNodeInfo<T> => v !== null && typeof v === 'object' && !Array.isArray(v) && 'nodeId' in v;
Try / catch
let source: RelatedNodeInfo | undefined;
try {
source = node.sourceNode;
} catch (e) {
if (e instanceof Error && e.message.includes('Source object must be')) {
const rel = node.relationships[NodeRelationship.SOURCE];
source = Array.isArray(rel) ? rel[0] : undefined;
} else throw e;
} Prevention
- Only mutate relationships via library helpers, not direct map writes.
- Normalize relationship shapes right after deserialization.
- Type relationship assignments narrowly so arrays are rejected by the compiler.
When it happens
Trigger: Reading node.sourceNode when node.relationships[NodeRelationship.SOURCE] was manually assigned an array, e.g. relationships: { [NodeRelationship.SOURCE]: [info] }.
Common situations: Hand-building node relationships instead of using node factories, or deserializing/copying relationship maps and wrapping values in arrays uniformly.
Related errors
- Previous object must be a single RelatedNodeInfo object
- Next object must be a single RelatedNodeInfo object
- Parent object must be a single RelatedNodeInfo object
- Child object must be a an array of RelatedNodeInfo objects
- Unknown strategy: ${strategy}
AI-assisted analysis of mastra-ai/mastra@75dd419e61 (2026-08-30).
Data as JSON: /api/errors/f7007fdc9e529843.
Report an issue: GitHub.