perspective-dev/perspective · error · std::runtime_error
Unhandled request type
Error message
Unhandled request type
What it means
The Perspective server's static helper `needs_poll()` classifies every incoming protobuf `Request` by its `ClientReqCase` oneof discriminator to decide whether polling is required. It throws "Unhandled request type" when the request's oneof case holds a value that is not listed in any branch of the switch — i.e. an enum value that exhausts neither the poll nor the no-poll list. This is a defensive fallthrough guard: it fires when a new request type was added to the proto without updating this dispatcher, or when the received enum value is unknown to this build.
Solutions
- Check that client and server use the same perspective version/proto so no unknown request types are sent.
- If you added a new request type to the proto, add the corresponding `case ReqCase::k...` to `needs_poll()` (and the other dispatchers like `entity_type_is_table`) in server.cpp.
- Log the raw request (`req.DebugString()` / numeric oneof case) before dispatch to identify which case value is slipping through.
- Rebuild both sides from the same source tree so generated proto enums match exactly.
Example fix
// before (server.cpp, needs_poll)
case ReqCase::kGetFeaturesReq:
case ReqCase::kMakeJoinTableReq:
return false;
case proto::Request::CLIENT_REQ_NOT_SET:
throw std::runtime_error("Unhandled request type 2");
}
throw std::runtime_error("Unhandled request type");
// after (handle the new request type explicitly)
case ReqCase::kGetFeaturesReq:
case ReqCase::kMakeJoinTableReq:
case ReqCase::kMyNewRequestReq: // newly added proto case
return false;
case proto::Request::CLIENT_REQ_NOT_SET:
throw std::runtime_error("Unhandled request type 2");
} Defensive patterns
Strategy: validation
Validate before calling
// Python client: verify the request oneof is populated before sending
# and that client/server proto versions match
assert req.WhichOneof("client_req") is not None, "empty Request"
# optionally check known-case coverage:
KNOWN_CASES = {"make_table_req", "table_size_req", "view_schema_req"} # etc.
assert req.WhichOneof("client_req") in KNOWN_CASES, (
f"server build may not know request type {req.WhichOneof('client_req')}") Type guard
// TypeScript/JS client over perspective WASM/socket transport
function isKnownRequestType(req: { [k: string]: unknown }): boolean {
const key = Object.keys(req).find((k) => k !== "reqId");
return key !== undefined && key !== "clientReqNotSet";
} Try / catch
// caller wraps the round-trip; server errors surface as a rejected/errored response
try {
const resp = await client.send(request);
} catch (e) {
if (String(e?.message).includes("Unhandled request type")) {
// version skew: server predates this request type — fall back or upgrade server
}
throw e;
} Prevention
- Pin client and server to the same perspective version in your dependency/lockfile.
- After upgrading the proto, rebuild the server and grep server.cpp for all `ReqCase::` switches to confirm the new case is classified.
- Log the oneof case name client-side before sending so mismatches are diagnosable.
- Add a smoke test that exercises every request type against the deployed server binary.
When it happens
Trigger: Sending the server a `Request` protobuf whose oneof case is set to a value not covered by `needs_poll()`'s switch (e.g. a newly added request kind compiled into the client but not into this server binary), or a corrupted/misencoded oneof tag that decodes to an out-of-range case value. Note it is NOT thrown for `CLIENT_REQ_NOT_SET` (that path throws "Unhandled request type 2" instead).
Common situations: Version mismatch between client and server (client built from a newer perspective-proto than the server), a custom fork adding new request types to `proto::Request` without updating `server.cpp` dispatchers, or a buggy/malformed serialization pipeline producing garbage oneof tags.
Understand the failure class
Background: Invalid enum value errors: "Unknown type", "Invalid scope", "must be one of" — when a string is not on the library's allowed list — this error's family across 23 libraries.
Related errors
AI-assisted analysis of perspective-dev/perspective@11c8238c0c (2026-09-09).
Data as JSON: /api/errors/c666d99818f20db6.
Report an issue: GitHub.
Appendix: source
Thrown at rust/perspective-server/cpp/perspective/src/cpp/server.cpp:1275
case ReqCase::kTableUpdateReq:
case ReqCase::kTableRemoveDeleteReq:
case ReqCase::kGetHostedTablesReq:
case ReqCase::kRemoveHostedTablesUpdateReq:
case ReqCase::kTableReplaceReq:
case ReqCase::kTableDeleteReq:
case ReqCase::kViewGetConfigReq:
case ReqCase::kViewColumnPathsReq:
case ReqCase::kViewDeleteReq:
case ReqCase::kViewExpressionSchemaReq:
case ReqCase::kViewRemoveOnUpdateReq:
case ReqCase::kServerSystemInfoReq:
case ReqCase::kGetFeaturesReq:
case ReqCase::kMakeJoinTableReq:
return false;
case proto::Request::CLIENT_REQ_NOT_SET:
throw std::runtime_error("Unhandled request type 2");
}
throw std::runtime_error("Unhandled request type");
}
static constexpr bool
entity_type_is_table(const proto::Request::ClientReqCase proto_case) {
using ReqCase = proto::Request::ClientReqCase;
switch (proto_case) {
case ReqCase::kTableSizeReq:
case ReqCase::kTableSchemaReq:
case ReqCase::kTableMakePortReq:
case ReqCase::kTableValidateExprReq:
case ReqCase::kMakeTableReq:
case ReqCase::kTableOnDeleteReq:
case ReqCase::kTableRemoveReq:
case ReqCase::kTableUpdateReq:
case ReqCase::kTableRemoveDeleteReq:
case ReqCase::kGetHostedTablesReq:
case ReqCase::kServerSystemInfoReq:View on GitHub (pinned to 11c8238c0c)