{"record":{"id":"4a2549c2fa97a83b","repo":"MemPalace/mempalace","slug":"qdrant-marker-remote-target-does-not-match-current","errorCode":null,"errorMessage":"qdrant marker remote target does not match current configuration ({details}); keep MEMPALACE_QDRANT_URL and namespace consistent or use a fresh palace directory","messagePattern":"qdrant marker remote target does not match current configuration \\((.+?)\\); keep MEMPALACE_QDRANT_URL and namespace consistent or use a fresh palace directory","errorType":"exception","errorClass":"BackendMismatchError","httpStatus":null,"severity":"error","filePath":"mempalace/backends/qdrant.py","lineNumber":1255,"sourceCode":"            raise BackendMismatchError(f\"qdrant marker is unreadable: {marker_path}\") from exc\n        return marker if isinstance(marker, dict) else {}\n\n    def _validate_marker_target(self, palace: PalaceRef, config: _QdrantConfig) -> None:\n        marker = self._read_marker(palace)\n        if marker is None:\n            return\n        if marker.get(\"backend\") != self.name:\n            raise BackendMismatchError(\"qdrant marker does not identify the qdrant backend\")\n        expected = self._marker_target(palace, config)\n        actual = marker.get(\"qdrant\")\n        if not isinstance(actual, dict):\n            raise BackendMismatchError(\"qdrant marker is missing remote target metadata\")\n        mismatched = [\n            key for key, expected_value in expected.items() if actual.get(key) != expected_value\n        ]\n        if mismatched:\n            details = \", \".join(mismatched)\n            raise BackendMismatchError(\n                \"qdrant marker remote target does not match current configuration \"\n                f\"({details}); keep MEMPALACE_QDRANT_URL and namespace consistent \"\n                \"or use a fresh palace directory\"\n            )\n\n    def _write_marker(self, palace: PalaceRef, config: _QdrantConfig) -> None:\n        if not palace.local_path:\n            return\n        os.makedirs(palace.local_path, exist_ok=True)\n        try:\n            os.chmod(palace.local_path, 0o700)\n        except (OSError, NotImplementedError):\n            pass\n        marker = {\n            \"backend\": self.name,\n            \"schema_version\": 1,\n            \"created_at\": _utcnow(),\n            \"palace_id\": palace.id,","sourceCodeStart":1237,"sourceCodeEnd":1273,"githubUrl":"https://github.com/MemPalace/mempalace/blob/06cb6987f02610784fefbad4b2bd5d026d164ba6/mempalace/backends/qdrant.py#L1237-L1273","documentation":"Raised when the marker's stored remote target (URL/namespace) differs from the current configuration. This is deliberate drift protection: a local palace pinned to Qdrant server A must not silently read/write Qdrant server B. The message lists the mismatched keys and advises keeping MEMPALACE_QDRANT_URL and the namespace consistent or using a fresh palace directory.","triggerScenarios":"MEMPALACE_QDRANT_URL or MEMPALACE_QDRANT_NAMESPACE (or the per-palace namespace) changed between sessions while reusing the same local palace directory; also when a per-palace config overrides the namespace so the computed expected target diverges from the marker.","commonSituations":"Switching between local and hosted Qdrant (localhost:6333 vs cloud URL); changing namespace to partition environments (dev/prod) but reusing a palace directory; copying a palace directory to another machine with different env vars; CI using a different namespace than the developer's machine.","solutions":["Restore the original MEMPALACE_QDRANT_URL/namespace values recorded in the marker file so they match the palace","If the change is intentional, use a fresh palace directory for the new target (or delete the marker and recreate with create=True after verifying the remote collection)","Read the marker file to see exactly which keys (url, namespace) mismatch and align config accordingly"],"exampleFix":"# before\nexport MEMPALACE_QDRANT_URL=http://qdrant-b:6333  # marker pins qdrant-a\ncol = backend.get_collection(palace, \"drawers\")  # raises BackendMismatchError\n# after\nexport MEMPALACE_QDRANT_URL=http://qdrant-a:6333  # match the pinned target\ncol = backend.get_collection(palace, \"drawers\")","handlingStrategy":"validation","validationCode":"import json, os\ndef config_matches_marker(palace_path: str, url: str, namespace: str, marker_name: str) -> bool:\n    try:\n        with open(os.path.join(palace_path, marker_name), encoding=\"utf-8\") as f:\n            target = json.load(f).get(\"qdrant\", {})\n    except (OSError, json.JSONDecodeError):\n        return False\n    return target.get(\"url\") == url and target.get(\"namespace\") == namespace","typeGuard":null,"tryCatchPattern":"from mempalace.backends.base import BackendMismatchError\ntry:\n    backend.get_collection(palace, name)\nexcept BackendMismatchError as e:\n    if \"does not match current configuration\" in str(e):\n        load_env_for_palace(palace)  # restore pinned URL/namespace or pick fresh dir","preventionTips":["Store the Qdrant URL/namespace used per palace in your own config and set env from it at startup","Use one palace directory per (server, namespace) pair","Never copy palace directories between environments without re-pinning"],"tags":["qdrant","configuration","drift","namespace"],"backgroundTag":null,"analyzedSha":"06cb6987f02610784fefbad4b2bd5d026d164ba6","analyzedAt":"2026-08-15T03:03:36.213Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}