{"record":{"id":"b34c4f2eb9a5a215","repo":"risingwavelabs/risingwave","slug":"no-frontend-worker-available","errorCode":null,"errorMessage":"no frontend worker available","messagePattern":"no frontend worker available","errorType":"exception","errorClass":"MetaError","httpStatus":null,"severity":"error","filePath":"src/meta/service/src/ddl_service.rs","lineNumber":1354,"sourceCode":"        Ok(Response::new(AlterStreamingJobConfigResponse {}))\n    }\n\n    /// Auto schema change for cdc sources,\n    /// called by the source parser when a schema change is detected.\n    async fn auto_schema_change(\n        &self,\n        request: Request<AutoSchemaChangeRequest>,\n    ) -> Result<Response<AutoSchemaChangeResponse>, Status> {\n        let req = request.into_inner();\n\n        // randomly select a frontend worker to get the replace table plan\n        let workers = self\n            .metadata_manager\n            .list_worker_node(Some(WorkerType::Frontend), Some(State::Running))\n            .await?;\n        let worker = workers\n            .choose(&mut thread_rng())\n            .ok_or_else(|| MetaError::from(anyhow!(\"no frontend worker available\")))?;\n\n        let client = self\n            .env\n            .frontend_client_pool()\n            .get(worker)\n            .await\n            .map_err(MetaError::from)?;\n\n        let Some(schema_change) = req.schema_change else {\n            return Err(Status::invalid_argument(\n                \"schema change message is required\",\n            ));\n        };\n\n        for table_change in schema_change.table_changes {\n            for c in &table_change.columns {\n                let c = ColumnCatalog::from(c.clone());\n","sourceCodeStart":1336,"sourceCodeEnd":1372,"githubUrl":"https://github.com/risingwavelabs/risingwave/blob/6469eb736d691e8e9b8a419a57edd6429ca77417/src/meta/service/src/ddl_service.rs#L1336-L1372","documentation":"In src/meta/service/src/ddl_service.rs:1354, the service lists running frontend worker nodes and randomly picks one to proxy the request; if the list is empty, `choose` returns None and this MetaError is produced. It is the steady-state guard for any DDL path that requires a live frontend.","triggerScenarios":"Invoking the DDL service operation at ddl_service.rs:1354 (frontend-proxied request) when no Frontend worker is in Running state — e.g. no frontend joined yet or all frontends are down.","commonSituations":"Meta-only operations issued directly against the meta node without a frontend in the cluster, or all frontends crashed mid-session.","solutions":["Start or restart frontend node(s) and confirm they reach Running state before retrying.","Check frontend meta-heartbeat connectivity/ports if frontends register but stay non-running.","Retry the request after the cluster scales back up; the pick is random per request.","If running meta-only tests, register a mock/real frontend worker before calling this DDL path."],"exampleFix":"// before: call with no running frontend\n// after\n$ ./risedev d  # start cluster incl. frontend\n$ ./risedev psql -c \"SHOW WORKERS;\"  # verify frontend RUNNING\n$ ./risedev psql -c \"<your ddl statement;>\"","handlingStrategy":"retry","validationCode":"const running = (await metaClient.listWorkers()).filter(w => w.type === 'Frontend' && w.state === 'Running');\nif (running.length === 0) throw new Error('Precheck: no frontend worker available');","typeGuard":"const hasFrontend = ws => Array.isArray(ws) && ws.some(w => w.workerType === 'FRONTEND' && w.state === 'RUNNING');","tryCatchPattern":"try {\n  await ddlClient.proxyOperation(req);\n} catch (e) {\n  if (e.message?.includes('no frontend worker available')) {\n    await backoffRetry(() => ddlClient.proxyOperation(req), { retries: 3, on: waitForFrontend });\n  } else { throw e; }\n}","preventionTips":["Run full clusters (meta + frontend) rather than meta-only for DDL operations.","Alert on frontend count dropping to zero.","Automate frontend restart and re-issue DDL when frontends fail."],"tags":["cluster","frontend","meta","availability"],"backgroundTag":"empty-result-set","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"}