{"record":{"id":"c666d99818f20db6","repo":"perspective-dev/perspective","slug":"unhandled-request-type","errorCode":null,"errorMessage":"Unhandled request type","messagePattern":"Unhandled request type","errorType":"exception","errorClass":"std::runtime_error","httpStatus":null,"severity":"error","filePath":"rust/perspective-server/cpp/perspective/src/cpp/server.cpp","lineNumber":1275,"sourceCode":"        case ReqCase::kTableUpdateReq:\n        case ReqCase::kTableRemoveDeleteReq:\n        case ReqCase::kGetHostedTablesReq:\n        case ReqCase::kRemoveHostedTablesUpdateReq:\n        case ReqCase::kTableReplaceReq:\n        case ReqCase::kTableDeleteReq:\n        case ReqCase::kViewGetConfigReq:\n        case ReqCase::kViewColumnPathsReq:\n        case ReqCase::kViewDeleteReq:\n        case ReqCase::kViewExpressionSchemaReq:\n        case ReqCase::kViewRemoveOnUpdateReq:\n        case ReqCase::kServerSystemInfoReq:\n        case ReqCase::kGetFeaturesReq:\n        case ReqCase::kMakeJoinTableReq:\n            return false;\n        case proto::Request::CLIENT_REQ_NOT_SET:\n            throw std::runtime_error(\"Unhandled request type 2\");\n    }\n    throw std::runtime_error(\"Unhandled request type\");\n}\n\nstatic constexpr bool\nentity_type_is_table(const proto::Request::ClientReqCase proto_case) {\n    using ReqCase = proto::Request::ClientReqCase;\n\n    switch (proto_case) {\n        case ReqCase::kTableSizeReq:\n        case ReqCase::kTableSchemaReq:\n        case ReqCase::kTableMakePortReq:\n        case ReqCase::kTableValidateExprReq:\n        case ReqCase::kMakeTableReq:\n        case ReqCase::kTableOnDeleteReq:\n        case ReqCase::kTableRemoveReq:\n        case ReqCase::kTableUpdateReq:\n        case ReqCase::kTableRemoveDeleteReq:\n        case ReqCase::kGetHostedTablesReq:\n        case ReqCase::kServerSystemInfoReq:","sourceCodeStart":1257,"sourceCodeEnd":1293,"githubUrl":"https://github.com/perspective-dev/perspective/blob/11c8238c0c9c0b9e490b5a6a2dc277afad1e980a/rust/perspective-server/cpp/perspective/src/cpp/server.cpp#L1257-L1293","documentation":"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.","triggerScenarios":"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).","commonSituations":"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.","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."],"exampleFix":"// before (server.cpp, needs_poll)\ncase ReqCase::kGetFeaturesReq:\ncase ReqCase::kMakeJoinTableReq:\n    return false;\ncase proto::Request::CLIENT_REQ_NOT_SET:\n    throw std::runtime_error(\"Unhandled request type 2\");\n}\nthrow std::runtime_error(\"Unhandled request type\");\n\n// after (handle the new request type explicitly)\ncase ReqCase::kGetFeaturesReq:\ncase ReqCase::kMakeJoinTableReq:\ncase ReqCase::kMyNewRequestReq:  // newly added proto case\n    return false;\ncase proto::Request::CLIENT_REQ_NOT_SET:\n    throw std::runtime_error(\"Unhandled request type 2\");\n}","handlingStrategy":"validation","validationCode":"// Python client: verify the request oneof is populated before sending\n# and that client/server proto versions match\nassert req.WhichOneof(\"client_req\") is not None, \"empty Request\"\n# optionally check known-case coverage:\nKNOWN_CASES = {\"make_table_req\", \"table_size_req\", \"view_schema_req\"}  # etc.\nassert req.WhichOneof(\"client_req\") in KNOWN_CASES, (\n    f\"server build may not know request type {req.WhichOneof('client_req')}\")","typeGuard":"// TypeScript/JS client over perspective WASM/socket transport\nfunction isKnownRequestType(req: { [k: string]: unknown }): boolean {\n  const key = Object.keys(req).find((k) => k !== \"reqId\");\n  return key !== undefined && key !== \"clientReqNotSet\";\n}","tryCatchPattern":"// caller wraps the round-trip; server errors surface as a rejected/errored response\ntry {\n  const resp = await client.send(request);\n} catch (e) {\n  if (String(e?.message).includes(\"Unhandled request type\")) {\n    // version skew: server predates this request type — fall back or upgrade server\n  }\n  throw e;\n}","preventionTips":["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."],"tags":["cpp","protobuf","server","grpc","dispatch"],"backgroundTag":"invalid-enum-value","analyzedSha":"11c8238c0c9c0b9e490b5a6a2dc277afad1e980a","analyzedAt":"2026-09-09T00:35:19.377Z","contentChangedAt":"2026-09-09T00:35:19.377Z","schemaVersion":2},"datasetVersion":"2026-09-17T15:17:12.973Z"}