{"record":{"id":"88c53bcaabdec0cd","repo":"risingwavelabs/risingwave","slug":"dml-is-not-permitted-during-cluster-recovery-no-a","errorCode":null,"errorMessage":"DML is not permitted during cluster recovery (no available table reader in streaming executors)","messagePattern":"DML is not permitted during cluster recovery \\(no available table reader in streaming executors\\)","errorType":"exception","errorClass":"DmlError","httpStatus":null,"severity":"error","filePath":"src/dml/src/error.rs","lineNumber":21,"sourceCode":"// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//     http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n/// The error type for DML operations.\n#[derive(thiserror::Error, Debug)]\npub enum DmlError {\n    #[error(\"table schema has changed, please try again later\")]\n    SchemaChanged,\n\n    #[error(\n        \"DML is not permitted during cluster recovery (no available table reader in streaming executors)\"\n    )]\n    NoReader,\n\n    #[error(\"table reader closed\")]\n    ReaderClosed,\n}\n\npub type Result<T> = std::result::Result<T, DmlError>;\n","sourceCodeStart":3,"sourceCodeEnd":31,"githubUrl":"https://github.com/risingwavelabs/risingwave/blob/6469eb736d691e8e9b8a419a57edd6429ca77417/src/dml/src/error.rs#L3-L31","documentation":"DmlError::NoReader is returned when a DML operation cannot proceed because no table reader is available in the streaming executors. This happens during cluster recovery: the streaming actors that would feed reads to the DML path are being recovered or are offline, so writes are temporarily not permitted.","triggerScenarios":"Executing INSERT/UPDATE/DELETE while the cluster is recovering (e.g. after a meta/worker failover) — the DML executor fails to obtain a table reader channel from the streaming framework.","commonSituations":"Writes sent immediately after a crash or failover before recovery completes; load balancers redirecting traffic to a node still recovering; automated ingestion pipelines not pausing during maintenance.","solutions":["Wait for cluster recovery to complete, then retry the write.","Check cluster health (`./risedev ctl cluster info` or meta dashboard) before resuming ingestion.","Configure ingestion clients to pause/retry on this error during maintenance windows."],"exampleFix":null,"handlingStrategy":"retry","validationCode":"// check cluster is healthy before writing\n// e.g. verify all workers are RUNNING via meta dashboard/ctl before resuming ingestion","typeGuard":null,"tryCatchPattern":"try { await insert(); }\ncatch (e) {\n  if (String(e).includes(\"no available table reader\")) { await waitForRecovery(); await insert(); }\n  else throw e;\n}","preventionTips":["Pause ingestion during failover/recovery maintenance","Gate writers on cluster health checks","Retry with exponential backoff after restarts"],"tags":["dml","recovery","availability"],"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-23T08:17:48.524Z"}