{"record":{"id":"dd2ebcdcc9a75895","repo":"jax-ml/jax","slug":"argument-to-get-c-api-topology-was-not-a-pjrt-c-ap","errorCode":null,"errorMessage":"Argument to get_c_api_topology was not a pjrt_c_api capsule.","messagePattern":"Argument to get_c_api_topology was not a pjrt_c_api capsule\\.","errorType":"validation","errorClass":"nb::value_error","httpStatus":null,"severity":"error","filePath":"jaxlib/jax.cc","lineNumber":607,"sourceCode":"      nb::arg(\"transfer_server_factory\").none() = std::nullopt,\n      nb::arg(\"force_dcn_cross_host_transfers\") = false,\n      nb::arg(\"sort_devices_by_process_index\") = true);\n  // TODO(b/322357665): Delete this method after TPU plugin changes to use the\n  // standard registration.\n  m.def(\"get_default_c_api_topology\",\n        [](std::string platform_name, std::string topology_name,\n           const absl::flat_hash_map<std::string, xla::PjRtValueType>& options)\n            -> std::shared_ptr<xla::ifrt::Topology> {\n          return std::make_shared<xla::ifrt::PjRtTopology>(xla::ValueOrThrow(\n              xla::GetCApiTopology(platform_name, topology_name, options)));\n        });\n  m.def(\"get_c_api_topology\",\n        [](nb::capsule c_api, std::string topology_name,\n           const absl::flat_hash_map<std::string, xla::PjRtValueType>& options)\n            -> std::shared_ptr<xla::ifrt::Topology> {\n          if (c_api.name() == nullptr ||\n              std::string_view(c_api.name()) != \"pjrt_c_api\") {\n            throw nb::value_error(\n                \"Argument to get_c_api_topology was not a pjrt_c_api capsule.\");\n          }\n          if (c_api.data() == nullptr) {\n            throw nb::value_error(\n                \"Argument to get_c_api_topology contained a null pointer.\");\n          }\n          return std::make_shared<xla::ifrt::PjRtTopology>(xla::ValueOrThrow(\n              xla::GetCApiTopology(static_cast<const PJRT_Api*>(c_api.data()),\n                                   topology_name, options)));\n        });\n  m.def(\"get_topology_for_devices\",\n        [](const std::vector<nb_class_ptr<PyDevice>>& py_devices) {\n          if (py_devices.empty()) {\n            throw nb::value_error(\n                \"get_topology_for_devices requires >= 1 devices.\");\n          }\n          auto client = py_devices[0]->client();\n          absl::InlinedVector<xla::ifrt::Device*, 1> ifrt_devices;","sourceCodeStart":589,"sourceCodeEnd":625,"githubUrl":"https://github.com/jax-ml/jax/blob/1e1c6a8fc06dfcd1247076ec5cae4640cea5d7bb/jaxlib/jax.cc#L589-L625","documentation":"get_c_api_topology requires a capsule whose name is exactly 'pjrt_c_api' so its data can be safely cast to PJRT_Api*; any other name is rejected before the topology query.","triggerScenarios":"jaxlib.get_c_api_topology(capsule, topology_name, options) with a capsule not produced by load_pjrt_plugin/get_backend_c_api, or whose name is null.","commonSituations":"Custom backend topology discovery passing a wrong or stale capsule object.","solutions":["Obtain the capsule via jax.extend.backend.get_backend_c_api() for the target platform","Check capsule name == 'pjrt_c_api' before calling"],"exampleFix":"# before\njaxlib.get_c_api_topology(cap, 'topo')\n# after\nfrom jax.extend import backend as jeb\njaxlib.get_c_api_topology(jeb.get_backend_c_api('tpu'), 'topo')","handlingStrategy":"validation","validationCode":"from jax.extend import backend as jeb\ncap = jeb.get_backend_c_api(platform)\nassert cap is not None","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Always source capsules from get_backend_c_api()"],"tags":["jax","pjrt","topology","capsule","validation"],"backgroundTag":"invalid-capsule-argument","analyzedSha":"1e1c6a8fc06dfcd1247076ec5cae4640cea5d7bb","analyzedAt":"2026-08-27T09:53:25.647Z","schemaVersion":2},"datasetVersion":"2026-08-27T13:17:12.746Z"}