Skip to content

feat(sozo): warn instead of error on RPC spec version mismatch#3402

Merged
kariy merged 4 commits intomainfrom
no-hard-error-on-rpc-mismatch
Apr 20, 2026
Merged

feat(sozo): warn instead of error on RPC spec version mismatch#3402
kariy merged 4 commits intomainfrom
no-hard-error-on-rpc-mismatch

Conversation

@kariy
Copy link
Copy Markdown
Member

@kariy kariy commented Apr 17, 2026

Summary

When a Starknet RPC node reports a starknet_specVersion that does not match the one sozo was built against (RPC_SPEC_VERSION = "0.9.0"), sozo aborted every command with:

Unsupported Starknet RPC version: <x>, expected 0.9.0.

This blocks users whenever a node publishes a spec bump, even though most RPC methods sozo uses are stable across minor bumps. This PR replaces the hard error in get_world_diff_and_provider with a ui.warn(...) and continues. If the node really is incompatible, the failure still surfaces at the actual RPC call site with a more specific error.

Parse failures on the version string (malformed response) are also downgraded to a warning, for the same reason.

Changes

  • bin/sozo/src/utils.rs: replace the early return Err(...) on version mismatch with a match that emits ui.warn(...) for both mismatch and parse failure paths, then proceeds.
  • is_compatible_version, RPC_SPEC_VERSION, and the 0.7/0.6 back-compat carve-out are unchanged.
  • No changes at the 11 call sites — they all go through get_world_diff_and_provider.

Test plan

  • cargo build -p sozo succeeds
  • cargo test -p sozo --bin sozo utils::tests:: passes (5/5 — unchanged is_compatible_version tests)
  • Manual smoke: point sozo at a katana/RPC with a mismatched spec version; commands should print the warning and continue instead of aborting

🤖 Generated with Claude Code

Summary by CodeRabbit

  • Bug Fixes
    • Improved handling of Starknet RPC version issues: the tool now warns and continues when the node reports an incompatible or unparseable version (or when the version query fails), instead of aborting. This reduces interruptions and improves robustness when interacting with nodes reporting unexpected RPC versions.

When the node reports a starknet_specVersion that does not match the one
sozo was built against, emit a warning via SozoUi and continue instead of
aborting the command. A genuinely incompatible RPC will still surface the
real failure at the call that actually breaks, with a much more specific
error than the blanket version gate. Parse failures on the version string
are also downgraded to a warning.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai bot commented Apr 17, 2026

Ohayo sensei! 🌸

Walkthrough

get_world_diff_and_provider no longer returns an error on Starknet RPC spec_version query or compatibility check failures. It matches the spec_version result, emits ui.warn on incompatible or parse-failure cases (or if querying fails), and continues to fetch chain_id and build the world diff.

Changes

Cohort / File(s) Summary
Error handling — RPC spec version
bin/sozo/src/utils.rs
Replaced propagated errors for provider.spec_version().await? and is_compatible_version(...) ? with a match that emits ui.warn on incompatibility, parse failures, or query errors, and continues execution to fetch chain_id and construct the world diff.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~10 minutes

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and concisely describes the main change: replacing error handling with warning behavior for RPC spec version mismatches, which matches the core functional change in the PR.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch no-hard-error-on-rpc-mismatch

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (1)
bin/sozo/src/utils.rs (1)

123-136: Consider treating spec_version() RPC failure the same way, sensei.

Right now line 123 still uses ?, so if the node responds but starknet_specVersion itself errors (e.g. method not exposed, transient RPC hiccup), sozo hard-fails before the new warn-and-continue path can help. Given the PR's stated goal — "let the actual incompatibility surface at the specific RPC call site" — it may be worth downgrading this to a warning too and proceeding with an unknown version assumption. Optional; happy to defer if the current scope is intentionally narrow.

♻️ Sketch
-    let spec_version = provider.spec_version().await?;
-    trace!(spec_version);
-
-    match is_compatible_version(&spec_version, RPC_SPEC_VERSION) {
-        Ok(true) => {}
-        Ok(false) => ui.warn(format!(
-            "Starknet RPC version mismatch: node reports {spec_version}, sozo was built \
-             against {RPC_SPEC_VERSION}. Continuing anyway; operations may fail if RPC \
-             methods differ."
-        )),
-        Err(e) => ui.warn(format!(
-            "Could not parse Starknet RPC version '{spec_version}': {e}. Continuing."
-        )),
+    match provider.spec_version().await {
+        Ok(spec_version) => {
+            trace!(spec_version);
+            match is_compatible_version(&spec_version, RPC_SPEC_VERSION) {
+                Ok(true) => {}
+                Ok(false) => ui.warn(format!(
+                    "Starknet RPC version mismatch: node reports {spec_version}, sozo \
+                     was built against {RPC_SPEC_VERSION}. Continuing anyway; operations \
+                     may fail if RPC methods differ."
+                )),
+                Err(e) => ui.warn(format!(
+                    "Could not parse Starknet RPC version '{spec_version}': {e}. Continuing."
+                )),
+            }
+        }
+        Err(e) => ui.warn(format!(
+            "Could not query Starknet RPC spec version: {e}. Continuing."
+        )),
     }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@bin/sozo/src/utils.rs` around lines 123 - 136, The call to
provider.spec_version() currently uses the ? operator and will hard-fail; change
it to handle errors like the version-parse path: call
provider.spec_version().await and match on Result, logging a ui.warn on Err
(including the error) and set spec_version to a safe "unknown" or empty value so
the subsequent is_compatible_version(&spec_version, RPC_SPEC_VERSION) check
runs; update references to spec_version, provider.spec_version(),
RPC_SPEC_VERSION, is_compatible_version, and ui.warn accordingly so failures to
fetch the RPC spec are downgraded to warnings and execution continues.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@bin/sozo/src/utils.rs`:
- Around line 126-136: CI failed due to rustfmt formatting in the new match
block around is_compatible_version/spec_version/RPC_SPEC_VERSION that calls
ui.warn; run the formatter and commit the changes by running `cargo fmt -p sozo`
(or `rustfmt` on bin/sozo/src/utils.rs) locally, verify the match block and
surrounding lines are reflowed, then stage and push the formatted file so the
repository contains the rustfmt-compliant version.

---

Nitpick comments:
In `@bin/sozo/src/utils.rs`:
- Around line 123-136: The call to provider.spec_version() currently uses the ?
operator and will hard-fail; change it to handle errors like the version-parse
path: call provider.spec_version().await and match on Result, logging a ui.warn
on Err (including the error) and set spec_version to a safe "unknown" or empty
value so the subsequent is_compatible_version(&spec_version, RPC_SPEC_VERSION)
check runs; update references to spec_version, provider.spec_version(),
RPC_SPEC_VERSION, is_compatible_version, and ui.warn accordingly so failures to
fetch the RPC spec are downgraded to warnings and execution continues.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 53fe3d9a-9f4e-4154-80d0-e2499f69e10d

📥 Commits

Reviewing files that changed from the base of the PR and between 4a374ac and ac73296.

📒 Files selected for processing (1)
  • bin/sozo/src/utils.rs

Comment thread bin/sozo/src/utils.rs Outdated
kariy and others added 2 commits April 17, 2026 16:07
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Extend the soften-on-version-stuff treatment to cover the case where
the starknet_specVersion RPC call itself fails (method not exposed,
transient network issue). Same rationale as the mismatch case: if the
node is genuinely incompatible, the real error surfaces at the specific
RPC call that breaks.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (1)
bin/sozo/src/utils.rs (1)

123-142: Ohayo sensei — warn-and-continue reads well.

The refactor cleanly covers all three paths (compatible, incompatible, parse/query failure) and matches the PR intent. Downstream RPC call sites will surface the real error if the node is truly incompatible, which is the right tradeoff over aborting every command on a version string mismatch.

One small nit you can take or leave: the three warn messages each end with a slightly different "Continuing..." tail ("Continuing anyway; ...", "Continuing.", "Continuing; ..."). Unifying the phrasing (e.g., always "Continuing; operations may fail if RPC methods differ.") would make the UX a touch more consistent, but it's purely cosmetic.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@bin/sozo/src/utils.rs` around lines 123 - 142, The three ui.warn messages in
the match over provider.spec_version() use slightly different trailing phrasing;
make them consistent by updating the messages emitted in the incompatible
branch, the parse error branch, and the query error branch to use the same tail
(for example: "Continuing; operations may fail if RPC methods differ."); locate
the block around provider.spec_version().await and change the strings passed to
ui.warn (in the is_compatible_version match's Ok(false) arm, the Err(e) parse
arm, and the Err(e) provider.spec_version() arm) so they all end with the
unified phrase while keeping the specific context text before it.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@bin/sozo/src/utils.rs`:
- Around line 123-142: The three ui.warn messages in the match over
provider.spec_version() use slightly different trailing phrasing; make them
consistent by updating the messages emitted in the incompatible branch, the
parse error branch, and the query error branch to use the same tail (for
example: "Continuing; operations may fail if RPC methods differ."); locate the
block around provider.spec_version().await and change the strings passed to
ui.warn (in the is_compatible_version match's Ok(false) arm, the Err(e) parse
arm, and the Err(e) provider.spec_version() arm) so they all end with the
unified phrase while keeping the specific context text before it.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: d3352013-9b2c-4808-9055-cb16850d1151

📥 Commits

Reviewing files that changed from the base of the PR and between ac73296 and 92ac691.

📒 Files selected for processing (1)
  • bin/sozo/src/utils.rs

@kariy
Copy link
Copy Markdown
Member Author

kariy commented Apr 20, 2026

The dojo tests are failing and should be fixed by #3403

@kariy kariy merged commit a6c6047 into main Apr 20, 2026
11 checks passed
@kariy kariy deleted the no-hard-error-on-rpc-mismatch branch April 20, 2026 17:15
@claude
Copy link
Copy Markdown

claude bot commented Apr 20, 2026

Claude finished @kariy's task —— View job


Documentation Analysis Complete

Task: Review PR #3402 changes and update documentation in dojoengine/book if user-facing behavior changed.

Todo list:

Analysis

Change Summary:
PR #3402 changes sozo's behavior when encountering a Starknet RPC spec version mismatch. Previously, sozo would abort with a fatal error (Unsupported Starknet RPC version: <x>, expected 0.9.0.). Now it warns and continues, allowing operations to proceed unless the incompatibility causes actual RPC call failures.

Documentation Search Results:

  • No existing documentation mentions RPC version mismatches, spec version errors, or this specific error message
  • The sozo documentation covers:
    • /toolchain/sozo/index.md - Overview and general usage
    • /toolchain/sozo/project-management.md - Development workflow, deployment
    • /toolchain/sozo/world-interaction.md - Runtime operations
    • /faq.md - Common questions (no RPC version issues mentioned)
  • RPC is mentioned only in context of configuration (rpc_url settings) but not error handling

Decision: No Documentation Updates Needed

Following the documentation rules strictly:

  1. DEFAULT TO NO CHANGES: There is no existing canonical location that documents RPC version handling or error behavior. The change removes a blocking error rather than adding a new feature or workflow.

  2. No logical home for this detail:

    • The sozo overview doesn't cover error handling specifics
    • Project management focuses on workflow, not internal error handling
    • World interaction covers runtime operations, not version compatibility
    • The FAQ addresses high-level questions, not implementation details
  3. Implementation detail, not user workflow: This change makes sozo more resilient by converting a hard error to a warning. Users don't need to take any action or change their workflow. They'll simply experience fewer disruptions.

  4. Creating new content would violate rules: Adding a new section like "RPC Version Compatibility" or "Troubleshooting" would contradict the "MINIMAL EDITS" and "DEFAULT TO NO CHANGES" principles. The change is about what sozo does internally when it detects a version mismatch, not about a user-facing feature.

Conclusion: No documentation updates required. The change improves internal error handling without introducing new user-facing features, workflows, or configuration requirements.


kariy added a commit to dojoengine/katana that referenced this pull request Apr 20, 2026
Updates the pinned dojoengine/dojo revision used by dojo-integration-test from v1.7.0-alpha.2 to a6c6047d5e038b83041e06ecfb704ab390981140 so the integration test runs against the current tip of dojo's main branch, which includes dojoengine/dojo#3402. Also bumps scarb from dev-2025-09-05 to 2.13.1 to match the cairo/starknet 2.13 pins in examples/spawn-and-move/Scarb.toml, and switches the project build step from sozo build to scarb build.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
kariy added a commit to dojoengine/katana that referenced this pull request Apr 20, 2026
Updates the pinned dojoengine/dojo revision used by dojo-integration-test from v1.7.0-alpha.2 to a6c6047d5e038b83041e06ecfb704ab390981140 so the integration test runs against the current tip of dojo's main branch, which includes dojoengine/dojo#3402. Also bumps scarb from dev-2025-09-05 to 2.13.1 to match the cairo/starknet 2.13 pins in examples/spawn-and-move/Scarb.toml, switches the project build step from sozo build to scarb build, and clones Dojo into /tmp/dojo instead of inside $GITHUB_WORKSPACE so proc-macro resolution during scarb build doesn't collide with Katana's root Cargo.toml workspace.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
kariy added a commit to dojoengine/katana that referenced this pull request Apr 20, 2026
Updates the pinned dojoengine/dojo revision used by dojo-integration-test from v1.7.0-alpha.2 to a6c6047d5e038b83041e06ecfb704ab390981140 so the integration test runs against the current tip of dojo's main branch, which includes dojoengine/dojo#3402. Also bumps scarb from dev-2025-09-05 to 2.13.1 to match the cairo/starknet 2.13 pins in examples/spawn-and-move/Scarb.toml, switches the project build step from sozo build to scarb build, clones Dojo into /tmp/dojo instead of inside \$GITHUB_WORKSPACE so proc-macro resolution during scarb build doesn't collide with Katana's root Cargo.toml workspace, and builds sozo from the cloned Dojo source so migrate runs with the sozo matching the revision under test instead of a stale asdf-installed release.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
kariy added a commit to dojoengine/katana that referenced this pull request Apr 20, 2026
Updates the pinned dojoengine/dojo revision used by dojo-integration-test from v1.7.0-alpha.2 to a6c6047d5e038b83041e06ecfb704ab390981140 so the integration test runs against the current tip of dojo's main branch, which includes dojoengine/dojo#3402. Also bumps scarb from dev-2025-09-05 to 2.13.1 to match the cairo/starknet 2.13 pins in examples/spawn-and-move/Scarb.toml, switches the project build step from sozo build to scarb build, clones Dojo into /tmp/dojo instead of inside \$GITHUB_WORKSPACE so proc-macro resolution during scarb build doesn't collide with Katana's root Cargo.toml workspace, builds sozo from the cloned Dojo source so migrate runs with the sozo matching the revision under test instead of a stale asdf-installed release, and starts Katana with --dev --dev.no-fee so sozo migrate transactions aren't rejected by the mempool's minimum L1 gas price check.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
kariy added a commit to dojoengine/katana that referenced this pull request Apr 21, 2026
Updates the pinned dojoengine/dojo revision used by dojo-integration-test from v1.7.0-alpha.2 to a6c6047d5e038b83041e06ecfb704ab390981140 so the integration test runs against the current tip of dojo's main branch, which includes dojoengine/dojo#3402. Also bumps scarb from dev-2025-09-05 to 2.13.1 to match the cairo/starknet 2.13 pins in examples/spawn-and-move/Scarb.toml, switches the project build step from sozo build to scarb build, clones Dojo into /tmp/dojo instead of inside \$GITHUB_WORKSPACE so proc-macro resolution during scarb build doesn't collide with Katana's root Cargo.toml workspace, builds sozo from the cloned Dojo source so migrate runs with the sozo matching the revision under test instead of a stale asdf-installed release, and starts Katana with --dev --dev.no-fee so sozo migrate transactions aren't rejected by the mempool. The no-fee flag is needed because Katana's genesis block header is initialized with GasPrices::MIN (1 wei) while the live gas oracle used by mempool validation returns 20 gwei, and sozo (via starknet-rs) estimates fees against BlockTag::Latest which points to genesis right after startup, so the estimated max L1 gas price ends up at 1 wei and gets rejected against the oracle's 20 gwei floor.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
kariy added a commit to dojoengine/katana that referenced this pull request Apr 21, 2026
Updates the pinned dojoengine/dojo revision used by
dojo-integration-test from v1.7.0-alpha.2 to
a6c6047d5e038b83041e06ecfb704ab390981140 so the integration test runs
against the current tip of dojo's main branch, which includes
dojoengine/dojo#3402. Also bumps scarb from
dev-2025-09-05 to 2.13.1 to match the cairo/starknet 2.13 pins in
examples/spawn-and-move/Scarb.toml, switches the project build step from
sozo build to scarb build, clones Dojo into /tmp/dojo instead of inside
$GITHUB_WORKSPACE so proc-macro resolution during scarb build doesn't
collide with Katana's root Cargo.toml workspace, builds sozo from the
cloned Dojo source so migrate runs with the sozo matching the revision
under test instead of a stale asdf-installed release, and starts Katana
with `--dev --dev.no-fee` so sozo migrate transactions aren't rejected
by the mempool. The no-fee flag is needed because Katana's genesis block
header is initialized with `GasPrices::MIN` (1 wei) while the live gas
oracle used by mempool validation returns 20 gwei, and sozo (via
starknet-rs) estimates fees against `BlockTag::Latest` which points to
genesis right after startup, so the estimated max L1 gas price ends up
at 1 wei and gets rejected against the oracle's 20 gwei floor.

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant