Handling binding errors
You might have tried to make a request and run into an error that looks like this:
Error: cannot find a matching binding to send the request: at least one of the
conditions must be met: (1) field `name` needs to be set and match the template:
'projects/*/secrets/*' OR (2) field `name` needs to be set and match the
template: 'projects/*/locations/*/secrets/*'
This is a binding error, and this guide explains how to troubleshoot binding errors.
What causes a binding error
The Google Cloud Client Libraries for Rust primarily use HTTP to send requests to Google Cloud services. An HTTP request uses a Uniform Resource Identifier (URI) to specify a resource.
Some RPCs correspond to multiple URIs. The contents of the request determine which URI is used.
The client library considers all possible URIs, and only returns a binding error if no URIs work. Typically this happens when a field is either missing or in an invalid format.
The example error above was produced by trying to get a resource without naming
the resource. Specifically, the name
field on a GetSecretRequest
was
required but not set.
let secret = client
.get_secret()
//.set_name("projects/my-project/secrets/my-secret")
.send()
.await;
How to fix it
In this case, to fix the error you'd set the name
field to something matching
one of the templates shown in the error message:
'projects/*/secrets/*'
'projects/*/locations/*/secrets/*'
Either allows the client library to make a request to the server:
let secret = client
.get_secret()
.set_name("projects/my-project/secrets/my-secret")
.send()
.await;
or
let secret = client
.get_secret()
.set_name("projects/my-project/locations/us-central1/secrets/my-secret")
.send()
.await;
Interpreting templates
The error message for a binding error includes a number of template strings
showing possible values for the request fields. Most template strings include
*
and **
as wildcards to match the field values.
Single wildcard
The *
wildcard alone means a non-empty string without a /
. It can be thought
of as the regex [^/]+
.
Here are some examples:
Template | Input | Match? |
---|---|---|
"*" | "simple-string-123" | true |
"projects/*" | "projects/p" | true |
"projects/*/locations" | "projects/p/locations" | true |
"projects/*/locations/*" | "projects/p/locations/l" | true |
"*" | "" (empty) | false |
"*" | "string/with/slashes" | false |
"projects/*" | "projects/" (empty) | false |
"projects/*" | "projects/p/" (extra slash) | false |
"projects/*" | "projects/p/locations/l" | false |
"projects/*/locations" | "projects/p" | false |
"projects/*/locations" | "projects/p/locations/l" | false |
Double wildcard
Less common is the **
wildcard, which means any string. The string can be
empty or contain any number of /
's. It can be thought of as the regex .*
.
Also, when a template ends in /**
, that initial slash is optionally included.
Template | Input | Match? |
---|---|---|
"**" | "" | true |
"**" | "simple-string-123" | true |
"**" | "string/with/slashes" | true |
"projects/*/**" | "projects/p" | true |
"projects/*/**" | "projects/p/locations" | true |
"projects/*/**" | "projects/p/locations/l" | true |
"projects/*/**" | "locations/l" | false |
"projects/*/**" | "projects//locations/l" | false |
Inspecting the error
If you need to inspect the error programmatically, you can do so by checking
that it is a binding error, then downcasting it to a BindingError
.
let secret = client
.get_secret()
//.set_name("projects/my-project/secrets/my-secret")
.send()
.await;
use gax::error::binding::BindingError;
let e = secret.unwrap_err();
assert!(e.is_binding(), "{e:?}");
assert!(e.source().is_some(), "{e:?}");
let _ = e
.source()
.and_then(|e| e.downcast_ref::<BindingError>())
.expect("should be a BindingError");