Skip to content

Carry a refusal's reason, metadata and request id in the JSON failure - #38

Merged
mrcrgl merged 1 commit into
mainfrom
error-metadata
Nov 3, 2026
Merged

mrcrgl merged 1 commit into
mainfrom
error-metadata

Conversation

@mrcrgl

@mrcrgl mrcrgl commented Nov 3, 2026

Copy link
Copy Markdown
Member

sdk-rust 0.6.0 exposes the ErrorInfo metadata of a refused call, and this CLI already pins a revision that has it. Before this change the CLI flattened every SDK error into one string, so a script had to parse the message to learn, for example, which service account a replayed create-service-account is about.

Changes

  • json failures from a call the API refused add three keys after code and description. Each is left out when the API sent none:

    • reason: the error code, such as CONFLICT;
    • metadata: what the reason names, such as {"serviceAccount": "organizations/o/serviceAccounts/sa-1"};
    • requestId: the id to quote to support.

    code stays "failure" and description is unchanged, so existing scripts keep working. Other failures, such as a local validation error or no credentials, print exactly as before.

  • Human formats: a metadata value the message doesn't already contain is printed under the message as key: value, the same way a refused field is. The replayed service account create's message already names the account, so its text output doesn't change.

  • How: api_error returns a typed output::Refused error. run_cli downcasts to it and prints a CommandResult::Refused. CommandResult now builds its JSON by hand, because serde's adjacent tagging can't put extra keys next to description. The JSON for success and for a plain failure is unchanged, and json_is_printed_as_it_always_was still passes.

  • README: the failure-format paragraph lists the new keys.

Testing

  • a_service_account_s_client_secret_comes_with_a_notice additionally checks that:
    • the replayed create's JSON carries reason, metadata.serviceAccount and requestId;
    • the description names the account only once.
  • a_refusal_s_metadata_the_message_doesn_t_name_is_said sends a 409 whose metadata names an instance the message doesn't. It checks that:
    • --output table prints it under the message;
    • the JSON carries it and leaves out an absent requestId.
  • a_refusal_adds_what_the_api_said_to_the_json_failure is a unit test of the envelope, with and without the keys.
  • Both integration tests fail without the change.
  • I ran these locally: cargo fmt --check, cargo clippy --workspace --all-targets with and without --all-features (-D warnings), cargo test --workspace, cargo test -p origincloud-cli --all-features, and scripts/generate.sh --check (current at api@6e3294ac3bab).

A call the API refused now fails with the error's code, its ErrorInfo
metadata and its request id apart, next to the envelope's code and
description in `json`, so a script reads the service account a replayed
create is about from `.metadata.serviceAccount` instead of parsing the
message. Each key is left out when the API sent none; the envelope's
`code` and `description` stay as they were.

The human formats say a metadata value under the message, as a refused
field is, when the message doesn't name it already.
@mrcrgl
mrcrgl merged commit 1641288 into main Nov 3, 2026
6 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant