Skip to content

[MPG Emitter] List operation prefix matching incorrectly assigns child resource list to parent resource #57216

@haiyuazhang

Description

@haiyuazhang

Bug Description

When a multi-path ARM resource (same model used at multiple URL paths) has its operations routed to a parent client via @@clientLocation, the List operation is incorrectly assigned to the parent resource instead of the child resource. CRUD operations (Create, Read, Delete) and Action operations are correctly assigned.

Root Cause

In resource-detection.ts, the emitter uses a two-pass approach:

  • Pass 1: CRUD operations (Read, Create, Update, Delete) establish resource paths
  • Pass 2: Non-CRUD operations (List, Action) are matched to existing resources via prefix matching

The prefix matching logic at approximately line 195-199:

const bestPrefixMatch = findLongestPrefixMatch(
  operationPath,
  existingPathsForModel,
  (path) => path.substring(0, path.lastIndexOf("/"))
);

strips the last segment from existing resource paths for comparison. For List operations, this causes the child resource's path to collapse into the parent resource's path, so the List gets assigned to the parent.

Reproduction

Spec: ServiceBus (specification/servicebus/resource-manager/Microsoft.ServiceBus/ServiceBus)

The SBAuthorizationRule model is used at 4 different paths (multi-path resource):

  • /namespaces/{name}/authorizationRules/{ruleName} (Namespace scope)
  • /namespaces/{name}/queues/{queue}/authorizationRules/{ruleName} (Queue scope)
  • /namespaces/{name}/topics/{topic}/authorizationRules/{ruleName} (Topic scope)
  • /namespaces/{name}/disasterRecoveryConfigs/{alias}/authorizationRules/{ruleName} (DR scope)

The Namespace-scope operations are routed via @@clientLocation to the "Namespaces" client in back-compatible.tsp:

@@clientLocation(SBAuthorizationRules.getAuthorizationRule, "Namespaces");
@@clientLocation(SBAuthorizationRules.createOrUpdateAuthorizationRule, "Namespaces");
@@clientLocation(SBAuthorizationRules.deleteAuthorizationRule, "Namespaces");
@@clientLocation(SBAuthorizationRules.listAuthorizationRules, "Namespaces");

With OverrideResourceName = "ServiceBusNamespaceAuthorizationRule" set on all CRUD operations via LegacyOperations template.

Result in armProviderSchema:

✅ CRUD + Action ops correctly go to ServiceBusNamespaceAuthorizationRule:

resourceName: ServiceBusNamespaceAuthorizationRule
  methods: [Create, Read, Delete, Action:listKeys, Action:regenerateKeys]

❌ List op incorrectly goes to ServiceBusNamespace:

resourceName: ServiceBusNamespace
  methods: [..., List:listAuthorizationRules, ...]

Why Actions work but List doesn't:

  • Action paths include the instance ID: .../authorizationRules/{ruleName}/listKeys → prefix matches auth rule resource ✅
  • List path does NOT include instance ID: .../authorizationRules → after lastIndexOf("/") stripping, matches Namespace resource ❌

Impact

The generated ServiceBusNamespaceAuthorizationRuleCollection is missing:

  • IEnumerable<ServiceBusNamespaceAuthorizationRuleResource> interface
  • IAsyncEnumerable<ServiceBusNamespaceAuthorizationRuleResource> interface
  • GetAll() / GetAllAsync() methods

Other scopes (Queue, Topic, DR) that have their own dedicated interfaces (not routed via @@clientLocation) generate correctly with all of the above.

Expected Behavior

The List operation listAuthorizationRules should be assigned to ServiceBusNamespaceAuthorizationRule resource (matching the CRUD operations), so the generated Collection class includes IEnumerable, GetAll, and GetAllAsync.

Suggested Fix

The prefix matching logic for List operations should consider the resource type extracted from the operation path, not just the path prefix. A List operation at .../authorizationRules should match the resource with type Microsoft.ServiceBus/namespaces/authorizationRules, not the parent Microsoft.ServiceBus/namespaces.

Environment

  • Emitter: @azure-typespec/http-client-csharp-mgmt@1.0.0-alpha.20260314.1
  • File: eng/packages/http-client-csharp-mgmt/emitter/src/resource-detection.ts

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugThis issue requires a change to an existing behavior in the product in order to be resolved.

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions