{"record":{"id":"c051a3290de4d637","repo":"clockworklabs/SpacetimeDB","slug":"invalid-publish-response","errorCode":null,"errorMessage":"Invalid publish response","messagePattern":"Invalid publish response","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/cli/src/subcommands/publish.rs","lineNumber":779,"sourceCode":"        println!(\"Publishing module...\");\n\n        builder = add_auth_header_opt(builder, &auth_header);\n\n        // Set the host type.\n        builder = builder.query(&[(\"host_type\", host_type)]);\n\n        let (content_type, payload) =\n            publication_body(&module_schema, program_bytes, environment.values, environment_options)?;\n        let res = builder\n            .header(reqwest::header::CONTENT_TYPE, content_type)\n            .body(payload)\n            .send()\n            .await?;\n        anyhow::ensure!(res.status().is_success(), \"Publish failed with HTTP {}\", res.status());\n        let response: PublishResult = res\n            .json()\n            .await\n            .map_err(|_| anyhow::anyhow!(\"Invalid publish response\"))?;\n        match response {\n            PublishResult::Success {\n                domain,\n                database_identity,\n                op,\n            } => {\n                let op = match op {\n                    PublishOp::Created => \"Created new\",\n                    PublishOp::Updated => \"Updated\",\n                };\n                if let Some(ref domain) = domain {\n                    println!(\"{op} database with name: {domain}, identity: {database_identity}\");\n                } else {\n                    println!(\"{op} database with identity: {database_identity}\");\n                }\n\n                if is_maincloud_host(&database_host)\n                    && let Some(domain) = domain.as_ref()","sourceCodeStart":761,"sourceCodeEnd":797,"githubUrl":"https://github.com/clockworklabs/SpacetimeDB/blob/eddf9f5014579a50d4b67630e28b6e15cad9c4af/crates/cli/src/subcommands/publish.rs#L761-L797","documentation":"After a successful (2xx) publish response, the CLI deserializes the body into `PublishResult`. If the body is missing or not valid JSON matching the expected shape, `res.json()` fails and this error is thrown. A 2xx status with a non-JSON body indicates the server (or an intermediary) did not return the expected publish result.","triggerScenarios":"Server returns 200 with an empty or HTML body; an intermediary (proxy, gateway) rewrites the response; server version returns a JSON shape the CLI's `PublishResult` enum cannot deserialize.","commonSituations":"Publishing through a corporate proxy that mangles responses; pointing the CLI at a non-SpacetimeDB endpoint; version skew between CLI and server changing the response format.","solutions":["Verify the `--server` URL points at a real Spacetimedb server, not a landing page or proxy.","Check CLI/server version compatibility (`spacetime --version`) and upgrade the CLI to match the server.","Inspect the raw response (curl the same endpoint with the same headers) to see what the body actually is.","Retry in case of a transient intermediary failure; bypass any proxy if possible."],"exampleFix":"// before\nspacetime publish --server https://gateway.example.com mydb  // 200 with HTML body -> Invalid publish response\n// after: target the SpacetimeDB API host directly\nspacetime publish --server https://spacetimedb.example.com mydb","handlingStrategy":"retry","validationCode":"// verify the endpoint speaks SpacetimeDB before publishing\ncurl -fsS \"$SERVER/v1/database/mydb/schema\" >/dev/null || echo \"not a SpacetimeDB API host\"","typeGuard":null,"tryCatchPattern":"// retry transiently on response-shape failures\nlet mut attempts = 0;\nloop {\n    match publish().await {\n        Err(e) if e.to_string().contains(\"Invalid publish response\") && attempts < 3 => {\n            attempts += 1; tokio::time::sleep(Duration::from_secs(2 * attempts)).await;\n        }\n        other => break other,\n    }\n}","preventionTips":["Point --server at the API host directly, avoiding rewriting proxies.","Keep CLI and server versions aligned.","Capture raw responses when debugging (curl with same headers) rather than guessing."],"tags":["json","publish","cli","response-parsing"],"backgroundTag":"unexpected-response-shape","analyzedSha":"eddf9f5014579a50d4b67630e28b6e15cad9c4af","analyzedAt":"2026-09-20T12:15:59.611Z","contentChangedAt":"2026-09-20T12:15:59.611Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}