{"record":{"id":"b25cf1cf55eac3d1","repo":"risingwavelabs/risingwave","slug":"table-schema-has-changed-please-try-again-later","errorCode":null,"errorMessage":"table schema has changed, please try again later","messagePattern":"table schema has changed, please try again later","errorType":"exception","errorClass":"DmlError","httpStatus":null,"severity":"warning","filePath":"src/dml/src/error.rs","lineNumber":18,"sourceCode":"// Copyright 2024 RisingWave Labs\n//\n// 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":1,"sourceCodeEnd":31,"githubUrl":"https://github.com/risingwavelabs/risingwave/blob/6469eb736d691e8e9b8a419a57edd6429ca77417/src/dml/src/error.rs#L1-L31","documentation":"DmlError::SchemaChanged indicates that a DML statement (INSERT/UPDATE/DELETE) was attempted against a table whose schema changed while the DML path was using a stale table descriptor/reader. The streaming executors hold cached schema snapshots; when the catalog version advances (e.g. a concurrent ALTER or MV refresh), the DML operation is aborted so the statement can be retried against the new schema.","triggerScenarios":"An INSERT/UPDATE/DELETE is in flight while the target table's schema is altered (or its catalog version changes), so the front-end/DML executor detects a mismatch between its cached schema and the current one.","commonSituations":"Long-running write workloads concurrent with `ALTER TABLE` / schema-change migrations; CI scripts that deploy schema changes while a data-ingestion job writes; retry storms after online DDL.","solutions":["Simply retry the DML statement — the message says 'please try again later'; it will be planned against the new schema.","Serialize schema changes with write workloads: pause ingestion during ALTER statements.","Upgrade the client/plan cache if the error repeats persistently after the change completes."],"exampleFix":"// before\nINSERT INTO t VALUES (1);  // fails during concurrent ALTER\n// after\n-- retry loop until schema change settles\nwhile (!insert_ok) { sleep(1s); INSERT INTO t VALUES (1); }","handlingStrategy":"retry","validationCode":null,"typeGuard":null,"tryCatchPattern":"for (let attempt = 0; attempt < 5; attempt++) {\n  try { await insert(); return; }\n  catch (e) {\n    if (String(e).includes(\"table schema has changed\")) { await sleep(1000); continue; }\n    throw e;\n  }\n}","preventionTips":["Schedule ALTER TABLE / schema migrations outside ingestion windows","Build retry-with-backoff into write pipelines","Monitor catalog version changes and pause writers during them"],"tags":["dml","schema","concurrency"],"backgroundTag":"schema-validation-failed","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"}