clockworklabs/SpacetimeDB · error
Invalid HTTP method
Error message
Invalid HTTP method
What it means
Panic in SpacetimeDB's host module environment when a SpacetimeDB module performs an outbound HTTP request. The module-facing `st_http::Method` enum includes an `Extension(String)` variant; extension methods are converted with `http::Method::from_bytes(...).expect("Invalid HTTP method")`. If the string is not a valid HTTP method token per RFC 7230 (only visible ASCII, no separators/control chars, non-empty), the conversion fails and the module's host call panics.
Solutions
- Sanitize or validate the method string before calling the HTTP host API: require non-empty ASCII token chars only (tchar set: `!#$%&'*+-.^_`|~`, digits, A-Z, a-z).
- Reject or fall back to a safe default (e.g. `GET`) when the method doesn't match `^[!#$%&'*+\-.^_`|~0-9A-Za-z]+$`.
- If you intended a standard verb, use the typed variant (e.g. `Method::Post`) instead of building an extension string.
- Upgrade the module SDK once HTTP host calls return typed errors instead of panicking for invalid methods.
Example fix
// before: passing raw user input as an HTTP method
let method = st_http::Method::Extension(user_input.clone());
client.request(method, uri, ...);
// after: validate the token before calling
fn valid_method_token(s: &str) -> bool {
!s.is_empty() && s.bytes().all(|b| b.is_ascii_graphic() && !b"()<>@,;:\\"/[]?={}".contains(&b))
}
let method = if valid_method_token(&user_input) {
st_http::Method::Extension(user_input)
} else { return Err(BadRequest::invalid_method(&user_input)); };
client.request(method, uri, ...); Defensive patterns
Strategy: validation
Validate before calling
fn valid_method_token(s: &str) -> bool {
!s.is_empty()
&& s.bytes().all(|b| {
b.is_ascii_alphanumeric() || b"!#$%&'*+-.^_`|~".contains(&b)
})
}
// reject before calling the HTTP host API
if !valid_method_token(&method_str) { return Err(InvalidMethod(method_str)); } Type guard
// Rust: narrow to the safe extension-method domain before the host call
fn safe_method(s: &str) -> Option<st_http::Method> {
valid_method_token(s).then(|| st_http::Method::Extension(s.to_owned()))
} Try / catch
let r = std::panic::catch_unwind(AssertUnwindSafe(|| client.request(m, uri, body)));
match r { Ok(res) => res?, Err(_) => return Err(HostCallPanic::invalid_method) } Prevention
- Never forward raw user/config input as an HTTP method; validate the RFC 7230 token charset first.
- Use typed standard methods (Method::Get, Method::Post) whenever the verb is known.
- Reject early at the module API boundary with a descriptive error instead of letting the host panic.
When it happens
Trigger: A module calls `HttpClient::request` (or similar host HTTP API) with `Method::Extension(method)` where `method` contains invalid token characters — spaces, unicode, control bytes, delimiters like `()<>@,;:\"/[]?={}`, or an empty string. Standard methods (GET/POST/…) map to constants and never hit this path.
Common situations: User-supplied or config-driven method strings passed verbatim into HTTP requests (e.g. treating method as free-form input); WebDAV/custom methods constructed by string concatenation that accidentally include whitespace or newlines; copy-pasting methods like `"GET "` with trailing space; generated clients forwarding arbitrary client input.
Related errors
- Failed to generate table due to validation errors
- table schema should validate for query builder codegen
- view schema should validate for query builder codegen
- cannot deserialize refs without a typespace
- cannot serialize refs without a typespace
AI-assisted analysis of clockworklabs/SpacetimeDB@eddf9f5014 (2026-08-20).
Data as JSON: /api/errors/cb4e49f365a25d0e.
Report an issue: GitHub.
Appendix: source
Thrown at crates/core/src/host/instance_env.rs:1329
method,
headers,
timeout,
uri,
version,
} = request;
let (mut request, ()) = http::Request::new(()).into_parts();
request.method = match method {
st_http::Method::Get => http::Method::GET,
st_http::Method::Head => http::Method::HEAD,
st_http::Method::Post => http::Method::POST,
st_http::Method::Put => http::Method::PUT,
st_http::Method::Delete => http::Method::DELETE,
st_http::Method::Connect => http::Method::CONNECT,
st_http::Method::Options => http::Method::OPTIONS,
st_http::Method::Trace => http::Method::TRACE,
st_http::Method::Patch => http::Method::PATCH,
st_http::Method::Extension(method) => http::Method::from_bytes(method.as_bytes()).expect("Invalid HTTP method"),
};
// The error type here, `http::uri::InvalidUri`, doesn't contain the URI itself,
// so it's safe to return and to log.
// See https://docs.rs/http/1.3.1/src/http/uri/mod.rs.html#120-141 .
request.uri = uri.try_into()?;
request.version = match version {
st_http::Version::Http09 => http::Version::HTTP_09,
st_http::Version::Http10 => http::Version::HTTP_10,
st_http::Version::Http11 => http::Version::HTTP_11,
st_http::Version::Http2 => http::Version::HTTP_2,
st_http::Version::Http3 => http::Version::HTTP_3,
};
request.headers = headers
.into_iter()
.map(|(k, v)| {
Ok((
// The error type here, `http::header::InvalidHeaderName`, doesn't contain the header name itself,
// so it's safe to return and to log.View on GitHub (pinned to eddf9f5014)