{"record":{"id":"09c974bc6c7b5011","repo":"risingwavelabs/risingwave","slug":"meta-storage-is-not-empty-before-being-restored","errorCode":null,"errorMessage":"Meta storage is not empty before being restored","messagePattern":"Meta storage is not empty before being restored","errorType":"error_code","errorClass":"BackupError","httpStatus":null,"severity":"error","filePath":"src/storage/backup/src/error.rs","lineNumber":54,"sourceCode":"        #[backtrace]\n        #[source]\n        BoxedError,\n    ),\n    #[error(\"Encoding error: {0}\")]\n    Encoding(\n        #[backtrace]\n        #[source]\n        BoxedError,\n    ),\n    #[error(\"Decoding error: {0}\")]\n    Decoding(\n        #[backtrace]\n        #[source]\n        BoxedError,\n    ),\n    #[error(\"Checksum mismatch: expected {expected}, found: {found}\")]\n    ChecksumMismatch { expected: u64, found: u64 },\n    #[error(\"Meta storage is not empty before being restored\")]\n    NonemptyMetaStorage,\n    #[error(transparent)]\n    Other(\n        #[from]\n        #[backtrace]\n        anyhow::Error,\n    ),\n}\n\nimpl From<std::io::Error> for BackupError {\n    fn from(err: std::io::Error) -> Self {\n        if err.kind() == std::io::ErrorKind::UnexpectedEof {\n            Self::Decoding(anyhow::anyhow!(\"unexpected EOF while decoding meta snapshot\").into())\n        } else {\n            Self::BackupStorage(err.into())\n        }\n    }\n}","sourceCodeStart":36,"sourceCodeEnd":72,"githubUrl":"https://github.com/risingwavelabs/risingwave/blob/6469eb736d691e8e9b8a419a57edd6429ca77417/src/storage/backup/src/error.rs#L36-L72","documentation":"`BackupError::NonemptyMetaStorage` is raised during restore when the target meta storage already contains data. Restoring into a non-empty meta store would overwrite or conflict with existing cluster metadata, so the operation refuses to proceed.","triggerScenarios":"Running a meta backup restore against a meta store that already has a cluster initialized (existing snapshots, workers, or metadata keys) instead of a fresh/empty meta store.","commonSituations":"Re-running a restore command without cleaning the meta store; pointing the restore at a live cluster's etcd; forgotten cleanup after a failed previous restore attempt.","solutions":["Point the restore at a fresh, empty meta store (new etcd instance or cleaned data directory).","If intentional, explicitly wipe the target meta storage before restoring (after confirming no live cluster depends on it).","Restore into a separate environment and switch over, instead of restoring in place."],"exampleFix":"// before: restore into existing meta store\n./risedev d default && restore backup\n// after: wipe meta store first\n./risedev k && rm -rf .risingwave/data && ./risedev d default && restore backup","handlingStrategy":"validation","validationCode":"// Ensure target meta store is empty before restore\nlet keys = meta_store.list_prefix(\"\").await?;\nif !keys.is_empty() {\n    return Err(\"refusing restore: target meta store is not empty\".into());\n}","typeGuard":null,"tryCatchPattern":"match restore().await {\n    Err(e @ BackupError::NonemptyMetaStorage) => {\n        tracing::error!(\"target meta store not empty; wipe it or point restore at a fresh store\");\n        // abort; require explicit operator confirmation to wipe\n    }\n    other => other?,\n}","preventionTips":["Always provision a fresh meta store for restores.","Script restore runs to include an explicit, confirmed wipe step.","Never restore over a live cluster's meta store; use a separate environment and cutover."],"tags":["backup","restore","meta-storage","rust"],"backgroundTag":"invalid-state-transition","analyzedSha":"6469eb736d691e8e9b8a419a57edd6429ca77417","analyzedAt":"2026-09-11T21:06:21.487Z","contentChangedAt":"2026-09-11T21:06:21.487Z","schemaVersion":2},"datasetVersion":"2026-09-14T16:17:12.679Z"}