{"record":{"id":"90e25aec71b5c1f9","repo":"jdx/mise","slug":"remote-cache-capability-protocol-is-incompatibl","errorCode":null,"errorMessage":"remote cache capability protocol {} is incompatible with client protocol {PROTOCOL_VERSION}","messagePattern":"remote cache capability protocol (.+?) is incompatible with client protocol (.+?)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/mise-cache-core/src/lib.rs","lineNumber":533,"sourceCode":"            .get_or_try_init(|| async {\n                let url = self.capabilities_endpoint()?;\n                let response = self\n                    .request(reqwest::Method::GET, url, \"application/json\")\n                    .await?\n                    .send()\n                    .await?;\n                if matches!(\n                    response.status(),\n                    StatusCode::NOT_FOUND\n                        | StatusCode::METHOD_NOT_ALLOWED\n                        | StatusCode::NOT_IMPLEMENTED\n                ) {\n                    return Ok(None);\n                }\n                let capabilities: RemoteCacheCapabilities =\n                    response.error_for_status()?.json().await?;\n                if capabilities.protocol.major != PROTOCOL_VERSION {\n                    bail!(\n                        \"remote cache capability protocol {} is incompatible with client protocol {PROTOCOL_VERSION}\",\n                        capabilities.protocol.major\n                    );\n                }\n                if !capabilities.features.blob_packs {\n                    return Ok(None);\n                }\n                let max_items = usize::try_from(capabilities.limits.max_batch_items)\n                    .ok()\n                    .filter(|limit| *limit > 0)\n                    .ok_or_else(|| {\n                        eyre!(\"remote cache blob packs require a positive max_batch_items limit\")\n                    })?;\n                if capabilities.limits.max_pack_bytes == 0 {\n                    bail!(\"remote cache blob packs require a positive max_pack_bytes limit\");\n                }\n                Ok(Some(BlobPackLimits {\n                    max_items: max_items.min(MAX_STAGED_BLOB_PACK_ITEMS),","sourceCodeStart":515,"sourceCodeEnd":551,"githubUrl":"https://github.com/jdx/mise/blob/6f52dcdf99e282ef7a7db68c81301fa4618d0f79/crates/mise-cache-core/src/lib.rs#L515-L551","documentation":"Thrown while fetching server capabilities (crates/mise-cache-core/src/lib.rs:533): the server responded 2xx with a RemoteCacheCapabilities JSON whose protocol.major != PROTOCOL_VERSION (currently 1). The client refuses to speak blob-pack protocol with an incompatible major version rather than misinterpret the wire format.","triggerScenarios":"Any first use of the remote cache that triggers the capabilities fetch (cached in a tokio OnceCell per client): GET v1/capabilities returns e.g. {\"protocol\":{\"major\":2,...}} while this client only speaks v1. Happens after upgrading the server but not the client, or pointing the client at a cache server built against a newer protocol.","commonSituations":"Server upgraded ahead of clients in a shared CI cache fleet; new protocol rollout where major was bumped for an incompatible pack format; pointing MISE remote cache config at a URL served by a different product that happens to respond to /capabilities.","solutions":["Upgrade mise (the client) to a version whose PROTOCOL_VERSION matches the server's advertised major — capabilities JSON shows exactly what the server speaks","If you operate the server, pin it to protocol major 1 until all clients are upgraded","Check the configured remote cache URL — a wrong base_url can hit an unrelated service whose /capabilities JSON parses but reports a different major","If you control both sides temporarily, disable blob packs on the server (features.blob_packs=false makes the client skip the incompatibility path only if the protocol major still matches — for major mismatch you must align versions)"],"exampleFix":null,"handlingStrategy":"fallback","validationCode":"let caps = client.capabilities().await?; // surfaced via the same fetch\nif let Some(c) = &caps && c.protocol.major != 1 {\n    return Err(\"server protocol too new; upgrade client or pin server to v1\");\n}","typeGuard":"fn server_is_v1(caps: &RemoteCacheCapabilities) -> bool {\n    caps.protocol.major == PROTOCOL_VERSION\n}","tryCatchPattern":"match client.capabilities().await {\n    Err(e) if e.to_string().contains(\"incompatible with client protocol\") => {\n        eprintln!(\"remote cache protocol mismatch — continuing without remote cache\");\n        None // degrade to local-only caching\n    }\n    other => other.ok().flatten(),\n}","preventionTips":["Pin the cache server version in lockstep with the mise client in CI fleets","Check the advertised protocol major at startup before jobs depend on the remote cache","Keep remote cache usage optional so a protocol mismatch degrades instead of failing builds"],"tags":["mise","cache","version","protocol-mismatch","capabilities"],"backgroundTag":"api-version-mismatch","analyzedSha":"6f52dcdf99e282ef7a7db68c81301fa4618d0f79","analyzedAt":"2026-08-22T10:14:23.840Z","schemaVersion":2},"datasetVersion":"2026-08-23T13:39:53.451Z"}