jax-ml/jax · error · nb::value_error
Argument to get_c_api_topology was not a pjrt_c_api capsule.
Error message
Argument to get_c_api_topology was not a pjrt_c_api capsule.
What it means
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.
Source
Thrown at jaxlib/jax.cc:607
nb::arg("transfer_server_factory").none() = std::nullopt,
nb::arg("force_dcn_cross_host_transfers") = false,
nb::arg("sort_devices_by_process_index") = true);
// TODO(b/322357665): Delete this method after TPU plugin changes to use the
// standard registration.
m.def("get_default_c_api_topology",
[](std::string platform_name, std::string topology_name,
const absl::flat_hash_map<std::string, xla::PjRtValueType>& options)
-> std::shared_ptr<xla::ifrt::Topology> {
return std::make_shared<xla::ifrt::PjRtTopology>(xla::ValueOrThrow(
xla::GetCApiTopology(platform_name, topology_name, options)));
});
m.def("get_c_api_topology",
[](nb::capsule c_api, std::string topology_name,
const absl::flat_hash_map<std::string, xla::PjRtValueType>& options)
-> std::shared_ptr<xla::ifrt::Topology> {
if (c_api.name() == nullptr ||
std::string_view(c_api.name()) != "pjrt_c_api") {
throw nb::value_error(
"Argument to get_c_api_topology was not a pjrt_c_api capsule.");
}
if (c_api.data() == nullptr) {
throw nb::value_error(
"Argument to get_c_api_topology contained a null pointer.");
}
return std::make_shared<xla::ifrt::PjRtTopology>(xla::ValueOrThrow(
xla::GetCApiTopology(static_cast<const PJRT_Api*>(c_api.data()),
topology_name, options)));
});
m.def("get_topology_for_devices",
[](const std::vector<nb_class_ptr<PyDevice>>& py_devices) {
if (py_devices.empty()) {
throw nb::value_error(
"get_topology_for_devices requires >= 1 devices.");
}
auto client = py_devices[0]->client();
absl::InlinedVector<xla::ifrt::Device*, 1> ifrt_devices;View on GitHub (pinned to 1e1c6a8fc0)
Solutions
- Obtain the capsule via jax.extend.backend.get_backend_c_api() for the target platform
- Check capsule name == 'pjrt_c_api' before calling
Example fix
# before
jaxlib.get_c_api_topology(cap, 'topo')
# after
from jax.extend import backend as jeb
jaxlib.get_c_api_topology(jeb.get_backend_c_api('tpu'), 'topo') Defensive patterns
Strategy: validation
Validate before calling
from jax.extend import backend as jeb cap = jeb.get_backend_c_api(platform) assert cap is not None
Prevention
- Always source capsules from get_backend_c_api()
When it happens
Trigger: 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.
Common situations: Custom backend topology discovery passing a wrong or stale capsule object.
Related errors
- c_api argument to load_pjrt_plugin is not a pjrt_c_api capsu
- Argument to get_c_api_topology contained a null pointer.
- Argument to register_custom_call_partitioner was not a pjrt_
- get_topology_for_devices requires >= 1 devices.
- {full_name} must be a pytree prefix with bool leaves or a tu
AI-assisted analysis of jax-ml/jax@1e1c6a8fc0 (2026-08-27).
Data as JSON: /api/errors/dd2ebcdcc9a75895.
Report an issue: GitHub.