Skip to content

Conversation

@AndrewAsseily
Copy link
Contributor

@AndrewAsseily AndrewAsseily commented Dec 2, 2025

Issue

CLI-5136 & CLI-7572 & #2688

Description of changes

Adds structured error formatting support for both AWS service errors and CLI exceptions. Users can now view errors in JSON, YAML, legacy, enhanced, text, or table formats using --cli-error-format.

For service errors (ClientError): Exposes modeled error members that AWS services return. For example, DynamoDB's TransactionCanceledException includes CancellationReasons with details about which operations failed.

For CLI exceptions: Provides structured output for errors like NoCredentialsError, NoRegionError, and ParamValidationError.

New --output off format: Suppresses all stdout output while preserving stderr

Examples

DynamoDB TransactionCanceledException

Command:

aws dynamodb transact-write-items \
  --transact-items '[
    {
      "Update": {
        "TableName": "TestErrorTable",
        "Key": {"id": {"S": "existing-item"}},
        "UpdateExpression": "SET #s = :val",
        "ExpressionAttributeNames": {"#s": "status"},
        "ExpressionAttributeValues": {":val": {"S": "updated"}},
        "ConditionExpression": "attribute_not_exists(id)"
      }
    },
    {
      "Put": {
        "TableName": "TestErrorTable",
        "Item": {"id": {"S": "new-item"}}
      }
    }
  ]'

Enhanced format (default):


aws: [ERROR]: An error occurred (TransactionCanceledException) when calling the TransactWriteItems operation: Transaction cancelled, please refer cancellation reasons for specific reasons [ConditionalCheckFailed, None]

Additional error details:
CancellationReasons: <complex value> (Use --cli-error-format with json or yaml to see full details)

JSON format (--cli-error-format json):

{
    "Message": "Transaction cancelled, please refer cancellation reasons for specific reasons [ConditionalCheckFailed, None]",
    "Code": "TransactionCanceledException",
    "CancellationReasons": [
        {
            "Code": "ConditionalCheckFailed",
            "Message": "The conditional request failed"
        },
        {
            "Code": "None"
        }
    ]
}

YAML format (--cli-error-format yaml):

CancellationReasons:
- Code: ConditionalCheckFailed
  Message: The conditional request failed
- Code: None
Code: TransactionCanceledException
Message: Transaction cancelled, please refer cancellation reasons for specific reasons
  [ConditionalCheckFailed, None]

Simple error with additional fields

Command:

aws s3api get-object --bucket not-a-real-bucket-0000 --key file.txt out.txt

Enhanced format:


aws: [ERROR]: An error occurred (NoSuchBucket) when calling the GetObject operation: The specified bucket does not exist

Additional error details:
BucketName: not-a-real-bucket-0000

JSON format:

{
  "Code": "NoSuchBucket",
  "Message": "The specified bucket does not exist",
  "BucketName": "not-a-real-bucket-0000"
}

Enhanced format behavior

The enhanced format handles different error shapes:

Simple values:

  • Strings, numbers, booleans, null
  • Small lists (≤5 simple items): AllowedValues: [GET, PUT, POST, DELETE]
  • Small dicts (≤5 simple key-value pairs): Metadata: {key1: value1, key2: value2}

Complex values:

  • Large collections (>5 items)
  • Nested structures (lists of dicts, nested dicts)
  • Mixed-type collections

When a field is complex, we show:

FieldName: <complex value>
(Use --cli-error-format with json or yaml to see full details)

Configuration

Config file (~/.aws/config):

[default]
cli_error_format = json

Environment variable:

export AWS_CLI_ERROR_FORMAT=yaml

Command-line flag:

aws <command> --cli-error-format enhanced

Valid formats: enhanced (default), json, yaml, text, table, legacy

Use legacy to get the old behavior with no structured error details.

Technical notes

AWS services return modeled error fields at the top level of the error response, not nested under the Error key. For example, DynamoDB returns CancellationReasons at response['CancellationReasons'], not response['Error']['CancellationReasons'].

The implementation:

  1. Copies all fields from response['Error'] (Code, Message, and any service-specific fields there)
  2. Merges in top-level fields from the response (excluding Error, ResponseMetadata, and duplicates)
  3. Returns the combined error dict

Tests

  • All existing tests pass

For reviewers

MAX_INLINE_ITEMS threshold:
Currently set to 5. Could be reduced to 4 for better terminal width compatibility, or we could add a character length limit (~70 chars) in addition to the item count. Open to feedback.

Sensitive data:
AWS service models include @sensitive traits for fields. Right now we display all error fields as returned by the service. Using the Smithy CLI to analyze AWS service models, I found 0 error response fields marked with @sensitive traits.

AndrewAsseily and others added 23 commits October 6, 2025 11:19
This fix addresses failures encountered on some systems when running the
startlivetail unit tests through the AWS CLI test runner script at
`scripts/ci/run-tests`. According to prompt toolkit documentation:

> During the creation of a prompt_toolkit Application, we can specify
> what input and output device to be used. By default, these are output
> objects that correspond with sys.stdin and sys.stdout. In unit tests
> however, we want to replace these.
> - For the input, we want a “pipe input”. This is an input device,
> in which we can programmatically send some input. It can be created
> with create_pipe_input(), and that return either a PosixPipeInput or a
> Win32PipeInput depending on the platform.

Reference: https://python-prompt-toolkit.readthedocs.io/en/stable/pages/advanced_topics/unit_testing.html

This change adds an optional `app_input`` parameter so that the test can
be run with `create_pipe_input()` to replace the input for unit testing.
@AndrewAsseily AndrewAsseily changed the base branch from nyandrew/str-std-error to feature/str-std-error December 3, 2025 20:33
ashovlin and others added 9 commits January 6, 2026 11:35
* ci: scope down GitHub Token permissions (aws#9804)

* ci: scope down permissions for fail-master-prs.yml

* ci: scope down permissions for run-bundle-test.yml

* ci: scope down permissions for changelog.yml

* ci: scope down permissions for update-lockfiles.yml

* ci: scope down permissions for run-tests.yml

* ci: scope down permissions for closed-issue-message.yml

* ci: scope down permissions for stale_community_prs.yml

* ci: scope down permissions for run-dep-tests.yml

* ci: scope down permissions for doc-pr-cherry-pick.yml

* ci: scope down permissions for source-dist-tests.yml

---------

Co-authored-by: Adnan Khan <[email protected]>
ashovlin and others added 20 commits January 8, 2026 11:28
…ing the expected error message format to include the new An error occurred (ParamValidation): prefix.
…test_suppresses_complex_response, test_suppresses_empty_response) into a single test_suppresses_response test
…mand.py by updating the expected error message to include the new An error occurred (ParamValidation): prefix.
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.