bug: Hardcoded CamelCase RPC method names fail with AxumRpcServer #80

Open
opened 2026-04-07 12:51:18 +00:00 by mahmoud · 1 comment
Owner

Problem

AxumRpcServer registers methods in lowercase (e.g. computeservice.get_vm), but several places in the codebase use CamelCase (e.g. ComputeService.get_vm) in hardcoded RPC calls. These calls silently return "Method not found" errors.

The UI RPC proxy was fixed (v0.1.6) by adding lowercase_method() to the /rpc and /explorer/rpc proxy handlers. But there are other call sites that bypass the proxy and construct RPC bodies directly — these are still broken.

Affected Locations

crates/hero_compute_ui/src/server.rs

Line Method Used By Impact
454 ComputeService.node_status /status health check handler Health check silently fails — server always shows "unavailable"
824 explorer.ExplorerService.get_vm Console WebSocket handler (explorer mode) Console 403 Forbidden in explorer mode
852 ComputeService.get_vm Console WebSocket handler (local mode) Console 403 Forbidden — "Method not found" returned as 403

crates/hero_compute_ui/static/js/dashboard.js

The browser JS sends CamelCase methods (ComputeService.node_status, ComputeService.deploy_vm, etc.) through the /rpc proxy. This is already fixed by lowercase_method() in the proxy handler. No JS changes needed.

Other crates to audit

Search for any hardcoded "method": with CamelCase in:

  • crates/hero_compute_server/src/ — heartbeat sender constructs RPC bodies
  • crates/hero_compute_explorer/src/ — proxy constructs RPC bodies
  • crates/hero_compute_examples/ — example code
  • crates/hero_compute/src/ — CLI

Symptoms

  • Console: Clicking console on a running VM returns 403 Forbidden with "Method not found"
  • Health check: /status endpoint may report server as unavailable even when it's running
  • Any inline RPC call: Returns empty or error response

Fix

Two approaches (pick one):

Option A: Lowercase all hardcoded method strings

Find-and-replace all hardcoded method names to lowercase:

// Before
"method": "ComputeService.get_vm"
// After  
"method": "computeservice.get_vm"

Simple but fragile — future code might reintroduce CamelCase.

Move lowercase_method() into http_rpc_unix() and http_rpc_tcp() so ALL RPC calls are automatically lowercased. No caller needs to worry about case.

pub async fn http_rpc_unix(socket_path: &str, rpc_path: &str, body: &str) -> Result<String, std::io::Error> {
    let body = lowercase_method(body);  // Always lowercase before sending
    // ... rest of function
}

This is the safest approach — it handles the JS proxy, inline Rust calls, and any future code.

Acceptance Criteria

  • Console works in local mode (no 403)
  • Console works in explorer mode (no 403)
  • /status health check returns correct server status
  • All hardcoded RPC calls use correct case
  • Grep for "method".*"[A-Z] in server.rs returns zero matches
  • Future RPC calls are automatically handled (Option B)
  • v0.1.6 partially fixed this for the /rpc proxy only
  • Same root cause: AxumRpcServer migration changed method dispatch from case-insensitive to case-sensitive
## Problem AxumRpcServer registers methods in **lowercase** (e.g. `computeservice.get_vm`), but several places in the codebase use **CamelCase** (e.g. `ComputeService.get_vm`) in hardcoded RPC calls. These calls silently return "Method not found" errors. The UI RPC proxy was fixed (v0.1.6) by adding `lowercase_method()` to the `/rpc` and `/explorer/rpc` proxy handlers. But there are **other call sites** that bypass the proxy and construct RPC bodies directly — these are still broken. ## Affected Locations ### `crates/hero_compute_ui/src/server.rs` | Line | Method | Used By | Impact | |------|--------|---------|--------| | 454 | `ComputeService.node_status` | `/status` health check handler | Health check silently fails — server always shows "unavailable" | | 824 | `explorer.ExplorerService.get_vm` | Console WebSocket handler (explorer mode) | Console 403 Forbidden in explorer mode | | 852 | `ComputeService.get_vm` | Console WebSocket handler (local mode) | Console 403 Forbidden — "Method not found" returned as 403 | ### `crates/hero_compute_ui/static/js/dashboard.js` The browser JS sends CamelCase methods (`ComputeService.node_status`, `ComputeService.deploy_vm`, etc.) through the `/rpc` proxy. This is **already fixed** by `lowercase_method()` in the proxy handler. No JS changes needed. ### Other crates to audit Search for any hardcoded `"method":` with CamelCase in: - `crates/hero_compute_server/src/` — heartbeat sender constructs RPC bodies - `crates/hero_compute_explorer/src/` — proxy constructs RPC bodies - `crates/hero_compute_examples/` — example code - `crates/hero_compute/src/` — CLI ## Symptoms - **Console**: Clicking console on a running VM returns `403 Forbidden` with "Method not found" - **Health check**: `/status` endpoint may report server as unavailable even when it's running - **Any inline RPC call**: Returns empty or error response ## Fix Two approaches (pick one): ### Option A: Lowercase all hardcoded method strings Find-and-replace all hardcoded method names to lowercase: ```rust // Before "method": "ComputeService.get_vm" // After "method": "computeservice.get_vm" ``` Simple but fragile — future code might reintroduce CamelCase. ### Option B: Lowercase at the transport layer (recommended) Move `lowercase_method()` into `http_rpc_unix()` and `http_rpc_tcp()` so ALL RPC calls are automatically lowercased. No caller needs to worry about case. ```rust pub async fn http_rpc_unix(socket_path: &str, rpc_path: &str, body: &str) -> Result<String, std::io::Error> { let body = lowercase_method(body); // Always lowercase before sending // ... rest of function } ``` This is the safest approach — it handles the JS proxy, inline Rust calls, and any future code. ## Acceptance Criteria - [ ] Console works in local mode (no 403) - [ ] Console works in explorer mode (no 403) - [ ] `/status` health check returns correct server status - [ ] All hardcoded RPC calls use correct case - [ ] Grep for `"method".*"[A-Z]` in `server.rs` returns zero matches - [ ] Future RPC calls are automatically handled (Option B) ## Related - v0.1.6 partially fixed this for the `/rpc` proxy only - Same root cause: AxumRpcServer migration changed method dispatch from case-insensitive to case-sensitive
Author
Owner

Recommendation: Option B — lowercase in the transport layer

Move lowercase_method() into http_rpc_unix() and http_rpc_tcp() in the SDK. Every RPC call goes through these two functions, so this is a single fix that covers:

  • The UI RPC proxy (/rpc, /explorer/rpc)
  • Inline RPC calls in the console handler, health check, etc.
  • Any future code that constructs RPC bodies

Once this is in the SDK, remove lowercase_method() from the UI's rpc_proxy handler — it becomes redundant.

Cleanup scope

While fixing this, also clean up outdated code from the AxumRpcServer migration:

  1. Remove SERVER_DOMAIN constant ("cloud") from the SDK — no longer used. The domain was needed by prepend_domain_to_method() which is already deleted.
  2. Remove any remaining "cloud." or "explorer." prefixes in hardcoded method strings — the domain is in the URL path, not the method name.
  3. Remove the lowercase_method() function from server.rs after moving it to the SDK transport layer.
  4. Audit crates/hero_compute_server/src/heartbeat_sender.rs — the heartbeat RPC body uses method names that may need lowercasing.
  5. Audit crates/hero_compute_explorer/src/explorer/proxy.rs — the explorer proxy also constructs RPC bodies.
  6. Fix the console handler's error mapping — "Method not found" should not return 403 Forbidden. Return 502 Bad Gateway or 500 Internal Server Error instead. 403 implies an auth failure which is misleading.

Goal: after this issue is closed, there should be zero CamelCase method strings in Rust code, and the transport layer guarantees lowercase for any future calls.

## Recommendation: Option B — lowercase in the transport layer Move `lowercase_method()` into `http_rpc_unix()` and `http_rpc_tcp()` in the SDK. Every RPC call goes through these two functions, so this is a single fix that covers: - The UI RPC proxy (`/rpc`, `/explorer/rpc`) - Inline RPC calls in the console handler, health check, etc. - Any future code that constructs RPC bodies Once this is in the SDK, **remove** `lowercase_method()` from the UI's `rpc_proxy` handler — it becomes redundant. ## Cleanup scope While fixing this, also clean up outdated code from the AxumRpcServer migration: 1. **Remove `SERVER_DOMAIN` constant** (`"cloud"`) from the SDK — no longer used. The domain was needed by `prepend_domain_to_method()` which is already deleted. 2. **Remove any remaining `"cloud."` or `"explorer."` prefixes** in hardcoded method strings — the domain is in the URL path, not the method name. 3. **Remove the `lowercase_method()` function from `server.rs`** after moving it to the SDK transport layer. 4. **Audit `crates/hero_compute_server/src/heartbeat_sender.rs`** — the heartbeat RPC body uses method names that may need lowercasing. 5. **Audit `crates/hero_compute_explorer/src/explorer/proxy.rs`** — the explorer proxy also constructs RPC bodies. 6. **Fix the console handler's error mapping** — "Method not found" should not return `403 Forbidden`. Return `502 Bad Gateway` or `500 Internal Server Error` instead. 403 implies an auth failure which is misleading. Goal: after this issue is closed, there should be zero CamelCase method strings in Rust code, and the transport layer guarantees lowercase for any future calls.
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
lhumina_code/hero_compute#80
No description provided.