{"record":{"id":"0810fc46b671865f","repo":"bytedance/deer-flow","slug":"failed-to-create-durable-migration-backup-backup","errorCode":null,"errorMessage":"Failed to create durable migration backup {backup_path}: {exc}","messagePattern":"Failed to create durable migration backup (.+?): (.+?)","errorType":"exception","errorClass":"OSError","httpStatus":null,"severity":"critical","filePath":"backend/packages/harness/deerflow/agents/memory/backends/deermem/deermem/core/storage.py","lineNumber":153,"sourceCode":"    except OSError:\n        return None\n\n\ndef _ensure_migration_backup(source_path: Path) -> Path:\n    \"\"\"Durably preserve one immutable pre-migration JSON source beside it.\"\"\"\n    backup_path = source_path.with_name(f\"{source_path.name}.v1.bak\")\n    try:\n        source_bytes = source_path.read_bytes()\n        if backup_path.exists():\n            if backup_path.read_bytes() != source_bytes:\n                raise MemoryStorageCorruption(f\"Existing migration backup {backup_path} differs from source {source_path}; the original backup was kept and migration was stopped\")\n            return backup_path\n        _atomic_write(backup_path, source_bytes)\n        return backup_path\n    except MemoryStorageCorruption:\n        raise\n    except OSError as exc:\n        raise OSError(f\"Failed to create durable migration backup {backup_path}: {exc}\") from exc\n\n\ndef _normalize_category(fact: dict[str, Any]) -> None:\n    raw_category = fact.get(\"category\", \"context\")\n    if not isinstance(raw_category, str):\n        raise ValueError(\"fact.category must be a string\")\n    category = raw_category or \"context\"\n    if category not in CORE_CATEGORIES:\n        fact.setdefault(\"categoryExtension\", category)\n        fact[\"category\"] = \"other\"\n\n\ndef _require_string_list(fact: dict[str, Any], field: str) -> None:\n    value = fact.get(field, [])\n    if not isinstance(value, list) or any(not isinstance(item, str) for item in value):\n        raise ValueError(f\"fact.{field} must be a list of strings\")\n    fact[field] = value\n","sourceCodeStart":135,"sourceCodeEnd":171,"githubUrl":"https://github.com/bytedance/deer-flow/blob/1dd6ba1acb03700589994b0366c5d1c7d05e2eff/backend/packages/harness/deerflow/agents/memory/backends/deermem/deermem/core/storage.py#L135-L171","documentation":"An OSError raised while creating or reading the durable .v1.bak migration backup is re-wrapped with context naming the backup path and the underlying error. It fires when reading source bytes or atomically writing the backup fails at the filesystem level. The migration is aborted before any canonical data is touched, so the source remains intact.","triggerScenarios":"Read-only or full disk; permission/ownership mismatch on the memory directory (e.g. container user changed); path length limits; the .v1.bak name already existing as a directory; NAS/network filesystem returning I/O errors.","commonSituations":"Docker volume mounted read-only or owned by root while the app runs as another user; disk-full conditions; migrating a memory directory copied between hosts with different UID mappings.","solutions":["Check the underlying OSError in the exception chain (errno): EACCES means fix ownership/permissions on the memory directory; ENOSPC means free space.","Remove the file or directory blocking the .v1.bak path if one exists with the wrong type.","Verify the memory directory is on a writable filesystem and fix the root cause before retrying; do not retry unchanged."],"exampleFix":null,"handlingStrategy":"retry","validationCode":"import os\n\ndef memory_dir_writable(path: str) -> bool:\n    return os.access(path, os.R_OK | os.W_OK)","typeGuard":null,"tryCatchPattern":"import errno, time\nfor attempt in range(3):\n    try:\n        store.migrate()\n        break\n    except OSError as exc:\n        if attempt == 2 or exc.errno not in (errno.EAGAIN, errno.EBUSY):\n            raise  # permanent (EACCES/ENOSPC) - fix cause first\n        time.sleep(0.5 * (attempt + 1))","preventionTips":["Verify write permissions and free disk space on the memory volume before upgrading.","Ensure the process user owns the memory directory (especially in containers).","Keep the .v1.bak pathname free of unrelated files or directories."],"tags":["deermem","memory","migration","filesystem","oserror"],"backgroundTag":null,"analyzedSha":"1dd6ba1acb03700589994b0366c5d1c7d05e2eff","analyzedAt":"2026-08-14T21:20:34.804Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}