Azure / Azure/azure-rest-api-specs
[BUG] Microsoft.Consumption/budgets: budgetName has no constraint in the spec, 1-63 in the docs and portal, and the service accepts up to 260 characters. Which is the contract?
- Dominant language
- TypeSpec
- Stars
- 3.1k
- Forks
- 5.9k
- Avg merge
- 2d 22h
- Merged PRs (30d)
- 444
Description
### API Spec link
https://github.com/Azure/azure-rest-api-specs/blob/main/specification/consumption/resource-manager/Microsoft.Consumption/Consumption/Budget.tsp
### API Spec version
2024-08-01 (same in every version from 2019-10-01 to 2026-06-01)
### Describe the bug
Four Microsoft sources disagree about what a valid `budgetName` is for `Microsoft.Consumption/budgets`, and I cannot tell which one is the contract.
| Source | What it says |
|---|---|
| This spec (`Budget.tsp`, line 21, and every generated `consumption.json` / `openapi.json`) | `NamePattern = ""`, no `minLength`, no `maxLength`. `budgetName` is a bare string. |
| Naming rules and restrictions page (learn.microsoft.com/azure/azure-resource-manager/management/resource-name-rules) | `budgets`, 1-63 characters, alphanumerics, hyphens and underscores |
| Azure portal, Create budget form | "The value must have a length of at most 63." and "Budget name must only contain alphanumeric, underscore or hyphen." |
| The live service | Accepts names up to 260 characters and almost any character; see below |
The newer `Microsoft.CostManagement/budgets` spec does declare `minLength: 1`, `maxLength: 63`, `pattern: ^[a-zA-Z0-9_-]+$` (`CostManagement/Budget.tsp`, lines 21 and 88-89). The Consumption spec never has. The naming rules row was added in 2021 by MicrosoftDocs/azure-docs#77506 from a screenshot of the portal form, with no service reference, and has not been changed since.
Downstream tooling has to pick one. The Terraform AzureRM provider, for example, enforces `^[-_a-zA-Z0-9]{1,63}$` on subscription budgets based on the docs row (hashicorp/terraform-provider-azurerm#21814), so it refuses names the service and the portal accept and display.
### Expected behavior
One contract, stated in the spec, that matches what the service enforces. Either:
1. The spec declares `minLength: 1`, `maxLength: 63`, `pattern: ^[a-zA-Z0-9_-]+$` for `budgetName`, matching the docs and the portal form, and the service is expected to enforce it (or the current permissiveness is documented as legacy behaviour clients must not rely on); or
2. The spec stays unconstrained because the service is intentionally permissive, and the naming rules page and the portal form are corrected to match.
Either answer is fine. What is not workable is the current state, where an SDK or provider author cannot tell whether a 64-character budget name is valid.
### Actual behavior
Tested on 25 and 26 August 2026 in my own tenant, at management group, subscription and resource group scope, with `az rest` against `Microsoft.Consumption/budgets`:
- Names up to 260 characters are accepted, stored, listed, updated and deleted intact, at all three scopes. Identical across api-versions 2019-10-01, 2021-10-01, 2023-03-01, 2023-11-01, 2024-08-01 and 2026-06-01.
- 261 characters and above fail with HTTP 401 `RBACAccessDenied`, which looks like the ARM resource-name segment limit (260 in the Resource Provider Contract), not a budget rule.
- The character set is far wider than "alphanumeric, underscore or hyphen": spaces, uppercase, leading hyphen or underscore, parentheses, `@`, `~`, `'`, `,`, `;`, `=`, accented and CJK characters are all accepted and stored as sent. The only rejected characters are the ones that break the URL path: `.` and `+` (HTML 404 from the gateway), `#` (`RBACAccessDenied`), `%` (`InvalidDoubleEncodedRequestUri`), `/`.
- The portal then lists, opens and offers Edit and Delete on both budgets, the 64-character one and the one with spaces and uppercase, neither of which its own Create form would accept.
- Editing `Portal says no` through the portal (amount 10 to 100, one alert condition added) saved successfully. The portal's own Edit form sent a PUT with the name its Create form rejects, and the service accepted it.
Example, subscription scope, api-version 2024-08-01, 64-character name:
```
PUT https://management.azure.com/subscriptions/{sub}/providers/Microsoft.Consumption/budgets/trictions_______________________________________________________?api-version=2024-08-01
{"properties":{"category":"Cost","amount":10,"timeGrain":"Monthly","timePeriod":{"startDate":"2026-08-01T00:00:00Z","endDate":"2028-07-31T00:00:00Z"}}}
201 Created
"name": "trictions_______________________________________________________" (64 characters)
```
Same request with the name `Portal says no`: 201 Created, name stored as sent. I chose that name because it contains spaces and uppercase letters, which the portal form refuses, so the name is the test.
### Reproduction Steps
```bash
SUB=$(az account show --query id -o tsv)
NAME="trictions$(printf '_%.0s' $(seq 1 55))" # 64 characters
az rest --method put \
--url "https://management.azure.com/subscriptions/$SUB/providers/Microsoft.Consumption/budgets/$NAME?api-version=2024-08-01" \
--body '{"properties":{"category":"Cost","amount":10,"timeGrain":"Monthly","timePeriod":{"startDate":"2026-08-01T00:00:00Z","endDate":"2028-07-31T00:00:00Z"}}}' \
--query '{name:name, length:length(name)}' -o json
# {"length": 64, "name": "trictions_______________________________________________________"}
# Then in the portal: Cost Management > Budgets > Add, type the same name. The form rejects it.
# Refresh the Budgets list: the budget created above is listed and can be opened, edited (amount, alerts) and deleted.
az rest --method delete --url "https://management.azure.com/subscriptions/$SUB/providers/Microsoft.Consumption/budgets/$NAME?api-version=2024-08-01"
```
### Questions for the service team
1. Is 1-63 with `^[a-zA-Z0-9_-]+$` the intended contract for `Microsoft.Consumption/budgets`? If so, should the spec declare it, and is the current service behaviour legacy tolerance that clients must not rely on?
2. If the service is intentionally permissive, should the naming rules page and the portal form be corrected, and is `Microsoft.CostManagement/budgets` (which does declare 1-63) the intended contract for new implementations?
3. Should SDK and provider authors validate Consumption budget names against the documented 1-63 rule, or defer to what the endpoint accepts?
### Environment
Azure CLI 2.x on Ubuntu (WSL2); Terraform 1.15.9 with AzureRM 5.2.0 for the management group scope checks. Not location-dependent.
Contributor guide
Research direction
Start with specification/consumption/resource-manager/Microsoft.Consumption/Consumption/Budget.tsp and compare it with CostManagement/Budget.tsp. Reproduce the discrepancy with the provided az rest commands and review the linked naming rules and portal behavior. Done means the service team selects one contract and the spec, validation guidance, and related documentation consistently state it.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- azure, openapi
- Domain
- api, cloud
- Issue type
- Bug
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Active
- Clarity
- Mostly clear
- Newbie friendliness
- 35/100