{"record":{"id":"a15f0c53f860a4fe","repo":"modelcontextprotocol/servers","slug":"entity-with-name-r-from-not-found","errorCode":null,"errorMessage":"Entity with name ${r.from} not found","messagePattern":"Entity with name (.+?) not found","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/memory/index.ts","lineNumber":223,"sourceCode":"      const newEntities = entities.filter((e, index) =>\n        !graph.entities.some(existingEntity => existingEntity.name === e.name) &&\n        // Also skip duplicates appearing earlier in this same batch\n        !entities.slice(0, index).some(earlier => earlier.name === e.name)\n      );\n      graph.entities.push(...newEntities);\n      await this.saveGraph(graph);\n      return newEntities;\n    });\n  }\n\n  async createRelations(relations: Relation[]): Promise<Relation[]> {\n    return this.withLock(async () => {\n      const graph = await this.loadGraph();\n      const entityNames = new Set(graph.entities.map(e => e.name));\n\n      relations.forEach(r => {\n        if (!entityNames.has(r.from)) {\n          throw new Error(`Entity with name ${r.from} not found`);\n        }\n        if (!entityNames.has(r.to)) {\n          throw new Error(`Entity with name ${r.to} not found`);\n        }\n      });\n\n      const isSameRelation = (a: Relation, b: Relation) =>\n        a.from === b.from &&\n        a.to === b.to &&\n        a.relationType === b.relationType;\n      const newRelations = relations.filter((r, index) =>\n        !graph.relations.some(existingRelation => isSameRelation(existingRelation, r)) &&\n        // Also skip duplicates appearing earlier in this same batch\n        !relations.slice(0, index).some(earlier => isSameRelation(earlier, r))\n      );\n      graph.relations.push(...newRelations);\n      await this.saveGraph(graph);\n      return newRelations;","sourceCodeStart":205,"sourceCodeEnd":241,"githubUrl":"https://github.com/modelcontextprotocol/servers/blob/d73f99efbfd40c3aa1b61e88728b3d49fb52608f/src/memory/index.ts#L205-L241","documentation":"MemoryServerGraph.createRelations() validates every requested relation against the set of entity names currently in the persisted knowledge graph before writing. If a relation's 'from' endpoint names an entity that does not exist, it throws immediately and no relations from the batch are created (the whole operation is atomic under the graph lock). The library refuses dangling relations so the graph never contains edges to or from nonexistent nodes.","triggerScenarios":"Calling createRelations([ { from: 'Alice', to: 'Bob', relationType: 'knows' } ]) when no entity named 'Alice' has been created via createEntities in the same graph file, or after the graph file was deleted/replaced, or when the entity name differs in case/whitespace from the stored one.","commonSituations":"Creating relations and entities in separate calls and passing wrong entity names; restoring a graph.json from a backup that lacks recently added entities; typos or case mismatches between createEntities and createRelations payloads; clients batching relations before the entity-creation call completes.","solutions":["Ensure all referenced entities exist first by calling createEntities with the same names before createRelations.","Load the current graph (readGraphFile / loadGraph) and diff your relation endpoints against entity names before submitting.","Check for exact string equality (case, trimming) between the 'from' name and the entity name used at creation time.","Catch the error and report which endpoint is missing rather than retrying blindly — retries will keep failing until the entity exists."],"exampleFix":"// before\nawait memory.createRelations([{ from: \"alice\", to: \"Bob\", relationType: \"knows\" }]);\n// after\nawait memory.createEntities([{ name: \"alice\", entityType: \"person\", observations: [] }]);\nawait memory.createRelations([{ from: \"alice\", to: \"Bob\", relationType: \"knows\" }]);","handlingStrategy":"validation","validationCode":"const graph = await memory.readGraph();\nconst names = new Set(graph.entities.map(e => e.name));\nconst missing = relations.filter(r => !names.has(r.from) || !names.has(r.to));\nif (missing.length) throw new Error(`Missing entities: ${[...new Set(missing.flatMap(r => [r.from, r.to]))].filter(n => !names.has(n)).join(\", \")}`);\nawait memory.createRelations(relations);","typeGuard":"function allEndpointsExist(relations: Relation[], names: Set<string>): boolean {\n  return relations.every(r => names.has(r.from) && names.has(r.to));\n}","tryCatchPattern":"try {\n  await memory.createRelations(relations);\n} catch (e) {\n  if (e instanceof Error && e.message.includes(\"not found\")) {\n    const name = e.message.match(/Entity with name (.+) not found/)?.[1];\n    await memory.createEntities([{ name: name!, entityType: \"unknown\", observations: [] }]);\n    await memory.createRelations(relations);\n  } else throw e;\n}","preventionTips":["Always create entities before relations in the same workflow.","Keep entity names in a shared constant/enum to avoid typos and case drift.","Diff intended relations against a fresh graph read before each batch write."],"tags":["knowledge-graph","missing-entity","validation","typescript"],"backgroundTag":"entity-not-found","analyzedSha":"d73f99efbfd40c3aa1b61e88728b3d49fb52608f","analyzedAt":"2026-09-07T14:54:21.545Z","contentChangedAt":"2026-09-07T14:54:21.545Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}