Skip to content

Azure CLI crashes on Python 3.14 due to unescaped % in argparse help strings #33409

@rangelovkiril

Description

@rangelovkiril

Describe the bug

Azure CLI crashes on Python 3.14 due to argparse becoming stricter about %-formatting in help strings. A help string containing a literal %Y (likely a datetime format example) is interpreted as a printf-style placeholder, causing ValueError: badly formed help string before the command even executes.

Related command

az ad sp create-for-rbac

Errors

The command failed with an unexpected error. Here is the traceback:
badly formed help string
Traceback (most recent call last):
File "/usr/lib/python3.14/argparse.py", line 1748, in _check_help
formatter._expand_help(action)
~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^
File "/usr/lib/python3.14/argparse.py", line 676, in _expand_help
return help_string % params
~~~~~~~~~~~~^~~~~~~~
ValueError: unsupported format character 'Y' (0x59) at index 77

The above exception was the direct cause of the following exception:

Traceback (most recent call last):
File "/opt/azure-cli/lib/python3.14/site-packages/knack/cli.py", line 233, in invoke
cmd_result = self.invocation.execute(args)
File "/opt/azure-cli/lib/python3.14/site-packages/azure/cli/core/commands/init.py", line 571, in execute
self.parser.load_command_table(self.commands_loader)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^
File "/opt/azure-cli/lib/python3.14/site-packages/azure/cli/core/parser.py", line 129, in load_command_table
param = AzCliCommandParser._add_argument(command_parser, arg)
File "/opt/azure-cli/lib/python3.14/site-packages/knack/parser.py", line 64, in _add_argument
return obj.add_argument(*scrubbed_options_list, **argparse_options)
~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/lib/python3.14/argparse.py", line 1562, in add_argument
self._check_help(action)
~~~~~~~~~~~~~~~~^^^^^^^^
File "/usr/lib/python3.14/argparse.py", line 1750, in _check_help
raise ValueError('badly formed help string') from exc
ValueError: badly formed help string
To check existing issues, please visit: https://github.com/Azure/azure-cli/issues

Issue script & Debug output

cli.knack.cli: Command arguments: ['ad', 'sp', 'create-for-rbac', '--role=Contributor', '--scopes=/subscriptions/e371e27b-febd-427a-bde4-1219053758f4', '--debug']
cli.knack.cli: init debug log:
Enable color in terminal.
cli.knack.cli: Event: Cli.PreExecute []
cli.knack.cli: Event: CommandParser.OnGlobalArgumentsCreate [<function CLILogging.on_global_arguments at 0x7fc90eba6ae0>, <function OutputProducer.on_global_arguments at 0x7fc90eaafc10>, <function CLIQuery.on_global_arguments at 0x7fc90eafa400>]
cli.knack.cli: Event: CommandInvoker.OnPreCommandTableCreate []
cli.azure.cli.core: Using packaged command index for profile 'latest'.
cli.azure.cli.core: Modules found from index for 'ad': ['azure.cli.command_modules.role']
cli.azure.cli.core: Loading command modules...
cli.azure.cli.core: Loaded command modules in parallel:
cli.azure.cli.core: Name Load Time Groups Commands
cli.azure.cli.core: role 0.004 17 62
cli.azure.cli.core: Total (1) 0.007 17 62
cli.azure.cli.core: Loaded 17 groups, 62 commands.
cli.azure.cli.core: Found a match in the command table.
cli.azure.cli.core: Raw command : ad sp create-for-rbac
cli.azure.cli.core: Command table: ad sp create
cli.azure.cli.core: remaining : for-rbac
cli.knack.cli: Event: CommandInvoker.OnPreCommandTableTruncate [<function AzCliLogging.init_command_file_logging at 0x7fc90e859bc0>]
cli.azure.cli.core.azlogging: metadata file logging enabled - writing logs to '/home/kiril/.azure/commands/2026-05-20.16-49-39.ad_sp_create-for-rbac.413991.log'.
az_command_data_logger: command args: ad sp create-for-rbac --role={} --scopes={} --debug
cli.knack.cli: Event: CommandInvoker.OnPreArgumentLoad [<function register_global_subscription_argument..add_subscription_parameter at 0x7fc90e88c1a0>]
cli.knack.cli: Event: CommandInvoker.OnPostArgumentLoad []
cli.knack.cli: Event: CommandInvoker.OnPostCommandTableCreate [<function register_ids_argument..add_ids_arguments at 0x7fc90e88f320>, <function register_global_policy_argument..add_global_policy_argument at 0x7fc90e88f3d0>, <function register_cache_arguments..add_cache_arguments at 0x7fc90e88f480>, <function register_upcoming_breaking_change_info..update_breaking_change_info at 0x7fc90e88f530>]
cli.azure.cli.core.azclierror: Traceback (most recent call last):
File "/usr/lib/python3.14/argparse.py", line 1748, in _check_help
formatter._expand_help(action)
~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^
File "/usr/lib/python3.14/argparse.py", line 676, in _expand_help
return help_string % params
~~~~~~~~~~~~^~~~~~~~
ValueError: unsupported format character 'Y' (0x59) at index 77

The above exception was the direct cause of the following exception:

Traceback (most recent call last):
File "/opt/azure-cli/lib/python3.14/site-packages/knack/cli.py", line 233, in invoke
cmd_result = self.invocation.execute(args)
File "/opt/azure-cli/lib/python3.14/site-packages/azure/cli/core/commands/init.py", line 571, in execute
self.parser.load_command_table(self.commands_loader)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^
File "/opt/azure-cli/lib/python3.14/site-packages/azure/cli/core/parser.py", line 129, in load_command_table
param = AzCliCommandParser._add_argument(command_parser, arg)
File "/opt/azure-cli/lib/python3.14/site-packages/knack/parser.py", line 64, in _add_argument
return obj.add_argument(*scrubbed_options_list, **argparse_options)
~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/lib/python3.14/argparse.py", line 1562, in add_argument
self._check_help(action)
~~~~~~~~~~~~~~~~^^^^^^^^
File "/usr/lib/python3.14/argparse.py", line 1750, in _check_help
raise ValueError('badly formed help string') from exc
ValueError: badly formed help string

cli.azure.cli.core.azclierror: The command failed with an unexpected error. Here is the traceback:
az_command_data_logger: The command failed with an unexpected error. Here is the traceback:
cli.azure.cli.core.azclierror: badly formed help string
Traceback (most recent call last):
File "/usr/lib/python3.14/argparse.py", line 1748, in _check_help
formatter._expand_help(action)
~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^
File "/usr/lib/python3.14/argparse.py", line 676, in _expand_help
return help_string % params
~~~~~~~~~~~~^~~~~~~~
ValueError: unsupported format character 'Y' (0x59) at index 77

The above exception was the direct cause of the following exception:

Traceback (most recent call last):
File "/opt/azure-cli/lib/python3.14/site-packages/knack/cli.py", line 233, in invoke
cmd_result = self.invocation.execute(args)
File "/opt/azure-cli/lib/python3.14/site-packages/azure/cli/core/commands/init.py", line 571, in execute
self.parser.load_command_table(self.commands_loader)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^
File "/opt/azure-cli/lib/python3.14/site-packages/azure/cli/core/parser.py", line 129, in load_command_table
param = AzCliCommandParser._add_argument(command_parser, arg)
File "/opt/azure-cli/lib/python3.14/site-packages/knack/parser.py", line 64, in _add_argument
return obj.add_argument(*scrubbed_options_list, **argparse_options)
~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/lib/python3.14/argparse.py", line 1562, in add_argument
self._check_help(action)
~~~~~~~~~~~~~~~~^^^^^^^^
File "/usr/lib/python3.14/argparse.py", line 1750, in _check_help
raise ValueError('badly formed help string') from exc
ValueError: badly formed help string
az_command_data_logger: badly formed help string
Traceback (most recent call last):
File "/usr/lib/python3.14/argparse.py", line 1748, in _check_help
formatter._expand_help(action)
~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^
File "/usr/lib/python3.14/argparse.py", line 676, in _expand_help
return help_string % params
~~~~~~~~~~~~^~~~~~~~
ValueError: unsupported format character 'Y' (0x59) at index 77

The above exception was the direct cause of the following exception:

Traceback (most recent call last):
File "/opt/azure-cli/lib/python3.14/site-packages/knack/cli.py", line 233, in invoke
cmd_result = self.invocation.execute(args)
File "/opt/azure-cli/lib/python3.14/site-packages/azure/cli/core/commands/init.py", line 571, in execute
self.parser.load_command_table(self.commands_loader)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^
File "/opt/azure-cli/lib/python3.14/site-packages/azure/cli/core/parser.py", line 129, in load_command_table
param = AzCliCommandParser._add_argument(command_parser, arg)
File "/opt/azure-cli/lib/python3.14/site-packages/knack/parser.py", line 64, in _add_argument
return obj.add_argument(*scrubbed_options_list, **argparse_options)
~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/lib/python3.14/argparse.py", line 1562, in add_argument
self._check_help(action)
~~~~~~~~~~~~~~~~^^^^^^^^
File "/usr/lib/python3.14/argparse.py", line 1750, in _check_help
raise ValueError('badly formed help string') from exc
ValueError: badly formed help string
To check existing issues, please visit: https://github.com/Azure/azure-cli/issues
cli.knack.cli: Event: Cli.PostExecute [<function AzCliLogging.deinit_cmd_metadata_logging at 0x7fc90e859e80>]
az_command_data_logger: exit code: 1
cli.main: Command ran in 0.281 seconds (init: 0.066, invoke: 0.215)
telemetry.main: Begin splitting cli events and extra events, total events: 1
telemetry.main: Finish splitting cli events and extra events, cli events: 1
telemetry.save: Save telemetry record of length 7993 in cache file under /home/kiril/.azure/telemetry/20260520164939373
telemetry.main: Begin creating telemetry upload process.
telemetry.process: Creating upload process: "/opt/azure-cli/bin/python /opt/azure-cli/lib/python3.14/site-packages/azure/cli/telemetry/init.py /home/kiril/.azure /home/kiril/.azure/telemetry/20260520164939373"
telemetry.process: Return from creating process 414017
telemetry.main: Finish creating telemetry upload process.

Expected behavior

The command should create a service principal and return its credentials, not crash during argument parsing.

Environment Summary

azure-cli 2.85.0 *

core 2.85.0 *
telemetry 1.1.0

Dependencies:
msal 1.35.1
azure-mgmt-resource 24.0.0

Python location '/opt/azure-cli/bin/python'
Config directory '/home/kiril/.azure'
Extensions directory '/home/kiril/.azure/cliextensions'

Python (Linux) 3.14.4 (main, May 3 2026, 17:15:29) [GCC 16.1.1 20260430]

Legal docs and information: aka.ms/AzureCliLegal

You have 2 update(s) available. Consider updating your CLI installation with 'az upgrade'

Additional context

The offending help strings are in azure/cli/command_modules/role/_params.py:

Line 188:

help='Display name of the service principal. If not present, default to azure-cli-%Y-%m-%d-%H-%M-%S '

Line 362:

time_help = 'The {} of the query in the format of %Y-%m-%dT%H:%M:%SZ, e.g. 2000-12-31T12:59:59Z. Defaults to {}'

The %Y, %m, %d, etc. are datetime format examples but are unescaped in argparse help strings, where % is a format specifier. Python 3.14 now strictly validates this via argparse._check_help.

Fix is to double the % signs (%%Y, %%m, etc.) in both lines. The other %Y occurrences in custom.py are safe — they're used with strftime(), not argparse.

Metadata

Metadata

Labels

Auto-AssignAuto assign by botAuto-ResolveAuto resolve by botAzure CLI TeamThe command of the issue is owned by Azure CLI teamGraph(doesn't work with label-triggered comments; use Graph.Microsoft instead) az adHelp CommandPossible-SolutionSimilar-IssueUpgradeaz upgradeact-identity-squadact-platform-engineering-squadcustomer-reportedIssues that are reported by GitHub users external to the Azure organization.questionThe issue doesn't require a change to the product in order to be resolved. Most issues start as that

Type

No type
No fields configured for issues without a type.

Projects

No projects

Relationships

None yet

Development

No branches or pull requests

Issue actions