{"record":{"id":"cbbfc9932b6ed221","repo":"cocoindex-io/cocoindex","slug":"name","errorCode":null,"errorMessage":"{name}","messagePattern":"\\{name\\}","errorType":"exception","errorClass":"KeyError","httpStatus":null,"severity":"error","filePath":"python/cocoindex/ops/entity_resolution/__init__.py","lineNumber":144,"sourceCode":"    \"\"\"Result of entity resolution.\n\n    Wraps the underlying ``name -> canonical | None`` dedup map and provides\n    safe chain-walking. Treat as read-only; mutations are not part of the\n    contract.\n    \"\"\"\n\n    _dedup: dict[str, str | None]\n\n    def canonical_of(self, name: str) -> str:\n        \"\"\"Return the canonical name for ``name``.\n\n        Returns ``name`` itself if it is already canonical. Raises\n        :exc:`KeyError` if unknown. Terminates without cycle detection\n        because the dedup map is acyclic by construction (see\n        requirement.md § \"Acyclic by construction\").\n        \"\"\"\n        if name not in self._dedup:\n            raise KeyError(name)\n        current = name\n        while True:\n            target = self._dedup[current]\n            if target is None:\n                return current\n            current = target\n\n    def canonicals(self) -> set[str]:\n        \"\"\"Set of all canonical names (entries whose value is None).\"\"\"\n        return {name for name, target in self._dedup.items() if target is None}\n\n    def groups(self) -> dict[str, set[str]]:\n        \"\"\"Map each canonical name to the set of all names that resolve to\n        it (including itself).\"\"\"\n        out: dict[str, set[str]] = {c: {c} for c in self.canonicals()}\n        for name in self._dedup:\n            out[self.canonical_of(name)].add(name)\n        return out","sourceCodeStart":126,"sourceCodeEnd":162,"githubUrl":"https://github.com/cocoindex-io/cocoindex/blob/e84aa99b3292c5270a4b313b2a7137ad9ce8ab3b/python/cocoindex/ops/entity_resolution/__init__.py#L126-L162","documentation":"DedupMap.canonical_of() walks the dedup chain to find the canonical name for an entity. If the name was never registered in the dedup map, a KeyError(name) is raised. The map is acyclic by construction, so lookup terminates.","triggerScenarios":"Calling canonical_of(name) (directly or via create_person_relations / groups) with a name that was never added to the dedup map via the merge/record API.","commonSituations":"Case/whitespace mismatches between the queried name and the registered one; processing a new entity batch before registering its aliases; stale map from a previous run.","solutions":["Register the name in the dedup map before calling canonical_of.","Normalize names (strip/case-fold) before both registration and lookup.","Wrap the call in try/except KeyError and treat the name as its own canonical form."],"exampleFix":"// before\ncanonical = mapper.canonical_of(name)\n// after\ntry:\n    canonical = mapper.canonical_of(name.strip().casefold())\nexcept KeyError:\n    canonical = name","handlingStrategy":"try-catch","validationCode":"if name not in mapper._dedup:\n    canonical = name  # or register it first","typeGuard":null,"tryCatchPattern":"try:\n    canonical = mapper.canonical_of(name)\nexcept KeyError:\n    canonical = name  # unknown names are their own canonical form","preventionTips":["Normalize (strip/casefold) names before registering and querying.","Register all entity aliases before running relation/group creation.","Decide a policy for unknown names (identity mapping vs. error)."],"tags":["python","keyerror","entity-resolution","lookup-failed"],"backgroundTag":"entity-not-found","analyzedSha":"e84aa99b3292c5270a4b313b2a7137ad9ce8ab3b","analyzedAt":"2026-09-08T15:59:19.997Z","contentChangedAt":"2026-09-08T15:59:19.997Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}