Hacktoberfest 2026: the issues maintainers tagged for October, open and beginner-friendly. Browse Hacktoberfest issues

[BUG] Expansion fails with "Hash must be finalized before the hash value is retrieved" when using an object output from a cross-scope module

Open
#3,909 0 comments 0 reactions 0 assignees View on GitHub

Maintainers usually reply within 4 days

Nobody has claimed this yet.

Assessment

Difficulty
4/5
Estimated time
3-5 days
Newbie friendliness
62/100
Issue type
Bug
Clarity
Clearly specified
Activity status
Active
Tech stack
azure, powershell

Research direction

Start by locating DeploymentVisitor.GetDeploymentScope and ExpressionHelpers.GetUnique, then reproduce the failure with the provided main.bicep, child.bicep, and assignments.bicep files with symbolicNameCodegen enabled. Done means the explicit cross-scope deployment resolves its object output correctly and guid() expands without the hash-finalization error or duplicate resource names.

Written by the indexing model from the issue text.

Description

Existing rule

N/A

Description of the issue

When a Bicep module is deployed to a different scope using the scope property (for example a nested management group), the resource ID recorded for the nested deployment does not account for the explicit scope.

DeploymentVisitor.GetDeploymentScope resolves the subscriptionId, resourceGroup and managementGroup properties of a deployment resource, but ignores the scope property. As a result the nested deployment is registered under its real scope, while the symbol resolves to the parent context scope. These do not match, so TemplateContext.TryGetResource fails to find the deployment.

reference() then falls back to a synthetic mock, and a chain such as reference('customRoles').outputs.policyReader.value.id resolves to an empty value instead of the expected string. When that empty value is passed to guid() as the last argument, expansion fails with:

Hash must be finalized before the hash value is retrieved

There are two defects here:

  1. The explicit scope property of a deployment resource is not used when calculating the resource ID, so cross-scope module outputs do not resolve.
  2. ExpressionHelpers.GetUnique only calls TransformFinalBlock when the final argument can be converted to a string. If it cannot, the hash is never finalized and reading HashAlgorithm.Hash throws. An argument that cannot be converted in any other position is silently skipped instead, which would produce a duplicate name rather than an error.
Error messages
Hash must be finalized before the hash value is retrieved

Inner stack trace:

at System.Security.Cryptography.HashAlgorithm.get_Hash()
at PSRule.Rules.Azure.Arm.Expressions.ExpressionHelpers.GetUnique(Object[] args)
at PSRule.Rules.Azure.Arm.Expressions.Functions.Guid(ITemplateContext context, Object[] args)
Reproduction

The module deployed with scope set to a child management group is required to reproduce the issue. Without scope the same template expands correctly.

main.bicep:

targetScope = 'managementGroup'

resource intermediateRoot 'Microsoft.Management/managementGroups@2023-04-01' = {
  scope: tenant()
  name: 'mg-intermediate-root'
  properties: {
    displayName: 'Intermediate Root'
  }
}

module customRoles './child.bicep' = {
  name: 'customRoles'
  scope: intermediateRoot
}

module roleAssignments './assignments.bicep' = {
  name: 'roleAssignments'
  scope: intermediateRoot
  params: {
    roleAssignments: [
      {
        principalId: '00000000-0000-0000-0000-000000000001'
        roleDefinitionId: customRoles.outputs.policyReader.id
      }
      {
        principalId: '00000000-0000-0000-0000-000000000002'
        roleDefinitionId: customRoles.outputs.policyReader.id
      }
    ]
  }
}

child.bicep:

targetScope = 'managementGroup'

resource roleDefinition 'Microsoft.Authorization/roleDefinitions@2022-04-01' = {
  name: guid('policyReader', managementGroup().id)
  properties: {
    roleName: 'Policy Reader'
    description: 'Read only access to policy.'
    type: 'CustomRole'
    permissions: [
      {
        actions: [
          'Microsoft.Authorization/policyAssignments/read'
        ]
      }
    ]
    assignableScopes: [
      managementGroup().id
    ]
  }
}

output policyReader object = {
  id: roleDefinition.id
  name: roleDefinition.name
}

assignments.bicep:

targetScope = 'managementGroup'

type roleAssignmentInput = {
  principalId: string
  roleDefinitionId: string
}

param roleAssignments roleAssignmentInput[]

resource roleAssignment 'Microsoft.Authorization/roleAssignments@2022-04-01' = [
  for assignment in roleAssignments: {
    name: guid(managementGroup().id, assignment.principalId, assignment.roleDefinitionId)
    properties: {
      principalId: assignment.principalId
      principalType: 'ServicePrincipal'
      roleDefinitionId: assignment.roleDefinitionId
    }
  }
]

Expansion of main.bicep fails. Reducing the name to guid(assignment.roleDefinitionId) also fails, which isolates the failure to that argument. Removing scope: intermediateRoot from the modules allows expansion to succeed.

The template requires symbolicNameCodegen to be enabled in bicepconfig.json to produce the reference('customRoles') form.

Version of PSRule

2.9.0

Version of PSRule for Azure

1.48.0

Additional context

Note that fixing only the hash finalization is not sufficient, and would be worse than the current behaviour. The unresolved argument would be silently skipped, so every role assignment sharing a principal would collapse to the same guid() value and expansion would emit duplicate resource names instead of an error. The scope resolution needs to be fixed so the value resolves correctly.

Dominant language
PowerShell
Stars
449
Forks
111
Avg merge
2d 18h
Merged PRs (30d)
11

Getting set up

Open in Codespaces

Starts the project's dev container in your browser, under your own GitHub account.

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

More from Azure/PSRule.Rules.Azure

All issues in Azure/PSRule.Rules.Azure

Similar issues

More Cloud issues

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.