Skip to content

fix: handle ARM expression strings in preflight resource fields - #7157

Merged
vhvb1989 merged 1 commit into
mainfrom
fix/preflight-arm-expression-fields
Mar 16, 2026
Merged

fix: handle ARM expression strings in preflight resource fields#7157
vhvb1989 merged 1 commit into
mainfrom
fix/preflight-arm-expression-fields

Conversation

@vhvb1989

Copy link
Copy Markdown
Member

Problem

When running azd up on Bicep templates that use conditional expressions for resource fields (e.g. identity: condition ? {...} : {...}), local preflight validation fails with:

parsing bicep snapshot: json: cannot unmarshal string into Go struct field
armTemplateResource.predictedResources.identity of type bicep.armTemplateIdentity

Bicep compiles conditional expressions into ARM expression strings like "[if(equals(...))]" instead of the expected typed JSON objects. The strongly-typed Go struct fields (*armTemplateIdentity, *armTemplateSKU, etc.) cannot unmarshal these strings.

Solution

Introduce a generic armField[T] type that stores raw JSON bytes and defers parsing:

  • Value() (T, bool) — typed access; returns false if the JSON is an ARM expression string
  • Raw() json.RawMessage — raw JSON bytes, always works regardless of shape
  • HasValue() bool — checks if the field was present and non-null

This gives callers the best of both worlds: fast typed access when the value is a real object, and graceful fallback when it's an ARM expression.

Applied to these fields in armTemplateResource:

Field Before After
Tags json.RawMessage armField[map[string]string]
SKU *armTemplateSKU armField[armTemplateSKU]
Plan *armTemplatePlan armField[armTemplatePlan]
Identity *armTemplateIdentity armField[armTemplateIdentity]
Copy *armTemplateCopy armField[armTemplateCopy]
Zones []string armField[[]string]

Properties remains json.RawMessage (no single typed target), Condition remains any (already flexible).

Testing

  • 7 new unit tests covering typed values, expression strings, null, absent fields, tags, and round-trip marshaling
  • All 47 existing bicep package tests pass unchanged

Fixes #7154

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Fixes local ARM preflight parsing failures when Bicep emits conditional resource fields as ARM expression strings (e.g. "[if(...)]") by deferring typed parsing and preserving raw JSON.

Changes:

  • Introduced a generic armField[T] wrapper that stores raw JSON and provides typed access via Value() when possible.
  • Updated armTemplateResource to use armField[...] for Tags, SKU, Plan, Identity, Copy, and Zones so expression-strings no longer break unmarshalling.
  • Added unit tests validating typed values, expression strings, absent/null handling, tags, and marshal/unmarshal round-tripping.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 2 comments.

File Description
cli/azd/pkg/infra/provisioning/bicep/local_preflight.go Adds armField[T] and migrates several armTemplateResource fields to tolerate ARM expression strings during snapshot parsing.
cli/azd/pkg/infra/provisioning/bicep/local_preflight_test.go Adds focused unit tests covering armField[T] behavior across typed/object values, expression strings, and basic round-trip marshaling.

You can also share your feedback on Copilot code review. Take the survey.

Comment thread cli/azd/pkg/infra/provisioning/bicep/local_preflight.go
Comment thread cli/azd/pkg/infra/provisioning/bicep/local_preflight.go
@vhvb1989
vhvb1989 force-pushed the fix/preflight-arm-expression-fields branch 4 times, most recently from 5af0d12 to 5af0d25 Compare March 16, 2026 18:17
Bicep conditional expressions (e.g. `identity: cond ? {...} : {...}`) compile
to ARM expression strings like `"[if(equals(...))]"` instead of typed objects.
This caused json.Unmarshal to fail when parsing the bicep snapshot during local
preflight validation.

Introduce a generic `armField[T]` type that stores raw JSON bytes and defers
parsing. Callers use `Value()` for typed access (returns ok=false for
expressions) or `Raw()` for the underlying JSON. Applied to Tags, SKU, Plan,
Identity, Copy, and Zones fields in armTemplateResource. Uses `omitzero` tag
and `IsZero()` method to preserve correct marshal behavior.

Fixes #7154

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@vhvb1989
vhvb1989 force-pushed the fix/preflight-arm-expression-fields branch from 5af0d25 to 6477793 Compare March 16, 2026 18:19
Comment thread cli/azd/pkg/infra/provisioning/bicep/local_preflight.go
Comment thread cli/azd/pkg/infra/provisioning/bicep/local_preflight.go

@weikanglim weikanglim left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Overall, this is perfectly fine for a tactical fix to address the immediate parsing failures.

It is possible that the proposed solution isn't completely exhaustive, I left two comments on potential places to look at.

One thing to perhaps consider: It does seem that the checks are on more experimental grounds with the reliance on snapshot, and failing provision outright doesn't seem quite right. I could see this failing if it were a dedicated command like validate.

@vhvb1989
vhvb1989 merged commit 17c2009 into main Mar 16, 2026
26 checks passed
Copilot AI mentioned this pull request Mar 16, 2026
jongio pushed a commit to jongio/azure-dev that referenced this pull request Mar 27, 2026
…e#7157)

Bicep conditional expressions (e.g. `identity: cond ? {...} : {...}`) compile
to ARM expression strings like `"[if(equals(...))]"` instead of typed objects.
This caused json.Unmarshal to fail when parsing the bicep snapshot during local
preflight validation.

Introduce a generic `armField[T]` type that stores raw JSON bytes and defers
parsing. Callers use `Value()` for typed access (returns ok=false for
expressions) or `Raw()` for the underlying JSON. Applied to Tags, SKU, Plan,
Identity, Copy, and Zones fields in armTemplateResource. Uses `omitzero` tag
and `IsZero()` method to preserve correct marshal behavior.

Fixes Azure#7154

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
jongio pushed a commit to jongio/azure-dev that referenced this pull request Mar 27, 2026
…e#7157)

Bicep conditional expressions (e.g. `identity: cond ? {...} : {...}`) compile
to ARM expression strings like `"[if(equals(...))]"` instead of typed objects.
This caused json.Unmarshal to fail when parsing the bicep snapshot during local
preflight validation.

Introduce a generic `armField[T]` type that stores raw JSON bytes and defers
parsing. Callers use `Value()` for typed access (returns ok=false for
expressions) or `Raw()` for the underlying JSON. Applied to Tags, SKU, Plan,
Identity, Copy, and Zones fields in armTemplateResource. Uses `omitzero` tag
and `IsZero()` method to preserve correct marshal behavior.

Fixes Azure#7154

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
jongio pushed a commit to jongio/azure-dev that referenced this pull request Mar 27, 2026
…e#7157)

Bicep conditional expressions (e.g. `identity: cond ? {...} : {...}`) compile
to ARM expression strings like `"[if(equals(...))]"` instead of typed objects.
This caused json.Unmarshal to fail when parsing the bicep snapshot during local
preflight validation.

Introduce a generic `armField[T]` type that stores raw JSON bytes and defers
parsing. Callers use `Value()` for typed access (returns ok=false for
expressions) or `Raw()` for the underlying JSON. Applied to Tags, SKU, Plan,
Identity, Copy, and Zones fields in armTemplateResource. Uses `omitzero` tag
and `IsZero()` method to preserve correct marshal behavior.

Fixes Azure#7154

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
jongio pushed a commit to jongio/azure-dev that referenced this pull request Mar 27, 2026
…e#7157)

Bicep conditional expressions (e.g. `identity: cond ? {...} : {...}`) compile
to ARM expression strings like `"[if(equals(...))]"` instead of typed objects.
This caused json.Unmarshal to fail when parsing the bicep snapshot during local
preflight validation.

Introduce a generic `armField[T]` type that stores raw JSON bytes and defers
parsing. Callers use `Value()` for typed access (returns ok=false for
expressions) or `Raw()` for the underlying JSON. Applied to Tags, SKU, Plan,
Identity, Copy, and Zones fields in armTemplateResource. Uses `omitzero` tag
and `IsZero()` method to preserve correct marshal behavior.

Fixes Azure#7154

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
jongio pushed a commit to jongio/azure-dev that referenced this pull request Mar 27, 2026
…e#7157)

Bicep conditional expressions (e.g. `identity: cond ? {...} : {...}`) compile
to ARM expression strings like `"[if(equals(...))]"` instead of typed objects.
This caused json.Unmarshal to fail when parsing the bicep snapshot during local
preflight validation.

Introduce a generic `armField[T]` type that stores raw JSON bytes and defers
parsing. Callers use `Value()` for typed access (returns ok=false for
expressions) or `Raw()` for the underlying JSON. Applied to Tags, SKU, Plan,
Identity, Copy, and Zones fields in armTemplateResource. Uses `omitzero` tag
and `IsZero()` method to preserve correct marshal behavior.

Fixes Azure#7154

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

AZD New Version Issue with Fabric (Agentic App)

4 participants