{"record":{"id":"f25a89ff2c21affc","repo":"MemPalace/mempalace","slug":"qdrant-marker-is-unreadable-marker-path","errorCode":null,"errorMessage":"qdrant marker is unreadable: {marker_path}","messagePattern":"qdrant marker is unreadable: (.+?)","errorType":"exception","errorClass":"BackendMismatchError","httpStatus":null,"severity":"error","filePath":"mempalace/backends/qdrant.py","lineNumber":1237,"sourceCode":"            \"namespace\": config.namespace,\n            \"palace_hash\": self._palace_hash(palace),\n            \"remote_prefix\": self._remote_collection_prefix(palace=palace, config=config),\n        }\n\n    def _marker_exists(self, palace: PalaceRef) -> bool:\n        return bool(palace.local_path and os.path.isfile(self._marker_path(palace.local_path)))\n\n    def _read_marker(self, palace: PalaceRef) -> Optional[dict]:\n        if not palace.local_path:\n            return None\n        marker_path = self._marker_path(palace.local_path)\n        if not os.path.isfile(marker_path):\n            return None\n        try:\n            with open(marker_path, encoding=\"utf-8\") as f:\n                marker = json.load(f)\n        except (OSError, json.JSONDecodeError) as exc:\n            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(","sourceCodeStart":1219,"sourceCodeEnd":1255,"githubUrl":"https://github.com/MemPalace/mempalace/blob/06cb6987f02610784fefbad4b2bd5d026d164ba6/mempalace/backends/qdrant.py#L1219-L1255","documentation":"Raised when the qdrant marker file (a small JSON file next to the palace that pins the palace to a specific Qdrant URL/namespace) exists but cannot be read or parsed. The backend treats an unreadable marker as a mismatch-protection failure rather than ignoring it, because silently proceeding could write to the wrong remote.","triggerScenarios":"_read_marker() hits an OSError (permissions, disk error, race where the file is removed mid-open) or json.JSONDecodeError (truncated/corrupted file, e.g. crash during write, manual editing, sync-tool conflict artifacts) while opening a collection or validating the marker target.","commonSituations":"Marker file corrupted by an interrupted write or power loss; file synced through Dropbox/git with merge-conflict contents; restrictive file permissions after copying a palace directory between users/machines; disk-full during marker write.","solutions":["Inspect the marker file (cat <palace>/qdrant-marker.json or equivalent) and check for truncation or conflict markers","If contents are unrecoverable, delete the marker and reinitialize with get_collection(..., create=True) after confirming the remote collection still exists","Fix filesystem permissions/ownership on the palace directory so the process can read it","Exclude palace directories from sync/merge tools that can corrupt single-file JSON"],"exampleFix":"// before\n# marker corrupted -> BackendMismatchError: qdrant marker is unreadable\ncol = backend.get_collection(palace, \"drawers\")\n// after\n# recover the remote target from Qdrant config, then re-pin the marker\nrm palacedir/qdrant-marker.json\ncol = backend.get_collection(palace, \"drawers\", create=True)  # rewrites marker","handlingStrategy":"validation","validationCode":"import json, os\ndef marker_readable(palace_path: str, marker_name: str) -> bool:\n    p = os.path.join(palace_path, marker_name)\n    if not os.path.isfile(p):\n        return True  # absent marker is fine\n    try:\n        with open(p, encoding=\"utf-8\") as f:\n            return isinstance(json.load(f), dict)\n    except (OSError, json.JSONDecodeError):\n        return False","typeGuard":null,"tryCatchPattern":"from mempalace.backends.base import BackendMismatchError\ntry:\n    col = backend.get_collection(palace, name)\nexcept BackendMismatchError as e:\n    if \"unreadable\" in str(e):\n        # repair: back up corrupt marker, delete it, re-pin with create=True\n        ...","preventionTips":["Write marker files atomically (temp file + rename)","Exclude palace directories from sync/merge tools","Back up palace marker files alongside data"],"tags":["qdrant","marker","corruption","filesystem"],"backgroundTag":null,"analyzedSha":"06cb6987f02610784fefbad4b2bd5d026d164ba6","analyzedAt":"2026-08-15T03:03:36.213Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}