Skip to content

Microsoft.Monitor/slis@2025-03-01-preview: ConditionOperator wire values rejected by ARM; spec/impl mismatch leaves no authoritative reference for non-portal users #43415

@torumakabe

Description

@torumakabe

Summary

For Microsoft.Monitor/slis@2025-03-01-preview, the ConditionOperator enum declared in the OpenAPI specification does not match what the ARM control plane actually accepts. As a result, every wire value declared in the spec is rejected with MalformedStructureError, while several undocumented values (e.g. EQ, In, NotIn, NotContains, NotStartsWith) are silently accepted. Numeric comparison operators (<, <=, >, >=) appear to have no working alias at all.

This makes the dimension-filter feature unusable for any non-portal authoring path (Bicep, Terraform AzAPI, raw REST, generated SDKs).

Spec reference

  • Repo: Azure/azure-rest-api-specs
  • File: specification/monitoringservice/resource-manager/Microsoft.Monitor/Slis/preview/2025-03-01-preview/openapi.json
  • Commit verified: 0fa038c6da5afc7cde4bf7429ca10d0465a3cacd

The ConditionOperator schema declares:

"enum": ["==", "!=", "<", "<=", ">", ">=",
         "@in", "!in",
         "startswith", "!startswith",
         "contains", "!contains"],
"x-ms-enum": {
  "name": "ConditionOperator",
  "modelAsString": true,
  "values": [
    {"name": "Equal", "value": "=="},
    {"name": "NotEqual", "value": "!="},
    {"name": "LessThan", "value": "<"},
    {"name": "LessThanOrEqual", "value": "<="},
    {"name": "GreaterThan", "value": ">"},
    {"name": "GreaterThanOrEqual", "value": ">="},
    {"name": "In", "value": "@in"},
    {"name": "NotIn", "value": "!in"},
    {"name": "StartsWith", "value": "startswith"},
    {"name": "NotStartsWith", "value": "!startswith"},
    {"name": "Contains", "value": "contains"},
    {"name": "NotContains", "value": "!contains"}
  ]
}

These are also the values reflected in the auto-generated Bicep/ARM template reference and the generated Azure.ResourceManager.Monitor.Slis .NET SDK.

Reproduction

Region: japaneast. Identical resource template, only the operator value changes:

{
  "properties": {
    "displayName": "operator-probe",
    "sliProperties": {
      "evaluationMethod": "RequestBased",
      "destinationMetrics": { "azureMonitorWorkspaceResourceId": "<AMW resource id>" },
      "compliancePeriodWindow": "P30D",
      "compliancePeriodAggregation": "Average",
      "spatialAggregation": "Average",
      "compliancePeriodWindowAggregation": "PT5M",
      "type": "Availability",
      "ratioBasedSli": {
        "goodSignals": [{
          "signalSources": [{
            "azureMonitorWorkspaceResourceId": "<AMW resource id>",
            "metricName": "<metric>",
            "temporalAggregation": "Total",
            "filters": [{
              "dimensionName": "<dim>",
              "operator": "<value under test>",
              "values": ["x"]
            }]
          }],
          "formula": "S0"
        }],
        "totalSignals": [/* same shape, no filters */]
      }
    }
  }
}

Observed behavior

Every value below was tested with az rest PUT against the same SLI ARM URI in the same subscription. MalformedStructureError is the response when ARM rejects the body before reaching the service.

Operator value tried Source Result
== spec wire value MalformedStructureError
!= spec wire value MalformedStructureError
< spec wire value MalformedStructureError
<= spec wire value MalformedStructureError
> spec wire value MalformedStructureError
>= spec wire value MalformedStructureError
@in spec wire value MalformedStructureError
!in spec wire value MalformedStructureError
!startswith spec wire value MalformedStructureError
!contains spec wire value MalformedStructureError
Equal x-ms-enum SDK name MalformedStructureError
LessThanOrEqual x-ms-enum SDK name MalformedStructureError
GreaterThan x-ms-enum SDK name MalformedStructureError
LT, LE, GT, GTE guessed MalformedStructureError
LessThan, LessThanOrEqualTo, Less, LessOrEqual guessed MalformedStructureError
EQ undocumented ✅ accepted
Eq undocumented ✅ accepted
In undocumented ✅ accepted
NotIn undocumented ✅ accepted
NotContains undocumented ✅ accepted
NotStartsWith undocumented ✅ accepted
contains (lowercase) matches spec wire value but not casing ✅ accepted
startswith (lowercase) matches spec wire value but not casing ✅ accepted

Two distinct problems:

  1. Spec/implementation mismatch. None of the spec-declared wire values work; instead an undocumented PascalCase set works. Generated clients and IaC users cannot reach this set.
  2. Numeric comparison operators have no working alias. No naming variant (<=, LE, LessThanOrEqual, LessOrEqual, …) is accepted, so dimension filters such as le <= 1 (Prometheus histogram bucket selection) are simply not expressible through this API today.

Impact

For our scenario (a histogram le bucket SLI on Microsoft.Monitor/accounts Prometheus metrics), this means we cannot write dimensionName=le, operator=LessThanOrEqual, values=["1"]. We had to abandon the histogram pattern and emit N separate metric names (metric_le_0p1, metric_le_0p5, …) to encode the bucket boundary in the metric name instead of as a label. This is non-idiomatic versus Prometheus convention, multiplies metric cardinality, and only became necessary because the documented operator surface does not work.

A ==-equivalent for histograms also does not help our case in particular, but it would solve the general case for users who want to filter Prometheus-style le="1" buckets, if the working EQ/Eq value were documented.

Public documentation gap

For non-portal authoring (Bicep / Terraform AzAPI / REST / generated SDKs), the OpenAPI spec is effectively the only source of truth for the signalSources[].filters[] schema. The Azure Monitor SLI conceptual / how-to documentation (Create service level indicators in Azure Monitor (preview)) mentions filters only abstractly:

Add filters such as a status code or dimension value to limit the values used for the calculation. … filter the good signal to count only requests with a 200 status code…

It does not document the operator enum, the wire values, or the dimensionName/value schema. Combined with the spec/implementation mismatch above, there is currently no public source from which an SDK or IaC user can derive a correct operator string, even though the service does accept undocumented values like EQ, In, NotIn, NotContains, and NotStartsWith.

Sibling Azure Monitor APIs do not have this issue

Dimension-filter operator enums in adjacent Azure Monitor APIs (verified against the same azure-rest-api-specs commit):

API Type Operator enum Status
Microsoft.Insights/metricAlerts (MetricDimension) metric alert free string; Include / Exclude by convention works
Microsoft.Insights/autoscalesettings (ScaleRuleMetricDimension) autoscale Equals, NotEquals works
Microsoft.Insights/scheduledQueryRules (Dimension) log alert Include, Exclude works
Microsoft.Monitor/slis (Condition) SLI 12 values incl. ==, <=, @in, !contains spec/impl mismatch

The SLI service is the only one in this family that declared a richer operator set than its peers, and is also the only one whose declared values do not match the implementation.

PromQL convention check

The destination metrics live in an Azure Monitor Workspace and are queried via PromQL. Note that PromQL itself does not have a <= label matcher — only =, !=, =~, !~. Histogram bucket selection in Prometheus is done by string equality on the le label (e.g. le="1" for the cumulative count of samples with duration ≤ 1s). So the rich numeric-comparison surface declared in the SLI spec is not actually required to express the canonical histogram pattern; an EQ-equivalent would suffice — provided one of the spec values worked, or the working value (EQ) were documented.

Expected behavior

Either:

  1. Fix the implementation to accept the spec-declared wire values (==, <=, @in, etc.), so SDKs and IaC users can rely on the documented contract; or
  2. Fix the spec to declare the values that ARM actually accepts (EQ, In, NotIn, NotContains, NotStartsWith, contains, startswith, …) and document precisely which dimension types each operator supports. If numeric comparison is not implemented, drop those values from the spec (and align with the simpler Include/Exclude style used by sibling Azure Monitor APIs).

In either case, please add an authoritative reference for the signalSources[].filters[] DSL — operator names, semantics, supported dimensionName / value shapes — to the Service level indicators conceptual docs so that non-portal users have something to read.

Environment

  • API version: 2025-03-01-preview
  • Region: japaneast
  • ARM endpoint: management.azure.com
  • Tested via: az rest --method PUT and Bicep deployment, both reproduce identically.
  • Tested: 2026-05-21

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions