Skip to content

fix(terraform): apply path parameter schema defaults in ImportState - #19

Open
AshGodfrey wants to merge 2 commits into
mainfrom
ash/terraform-import-state-path-param-defaults
Open

AshGodfrey wants to merge 2 commits into
mainfrom
ash/terraform-import-state-path-param-defaults

Conversation

@AshGodfrey

@AshGodfrey AshGodfrey commented Sep 15, 2026

Copy link
Copy Markdown
Contributor

Why

When a resource's read operation has a path parameter with a schema default, the generated resource schema applies it (Computed + Optional + a static default), and refresh works with it unset. The generated ImportState did not: the field was still mandatory in the JSON import ID and importing without it failed with:

Error: Missing required field
The field workspace is required but was not found in the json encoded ID.

This forces users to know and pass a value that every other code path already defaults, and blocks adding a defaulted path parameter to an existing resource without breaking established import workflows.

What changed

templates/templates/terraform/includes/generateImportState.ts:

  • Fields with a schema default are decoded as pointers in the import JSON struct, so an omitted field is distinguishable from a zero value.
  • When such a field is omitted, ImportState assigns the schema default and continues instead of returning an error. Global fields still try the provider-level value first, then the default.
  • Fields without a default behave exactly as before.

Generated output for a defaulted string path parameter:

if data.Workspace == nil {
	var workspaceDefault string = `default-workspace`
	data.Workspace = &workspaceDefault
}
resp.Diagnostics.Append(resp.State.SetAttribute(ctx, path.Root("workspace"), data.Workspace)...)

Review spec and provider:

  • Adds an ImportDefaultedId resource to tests/specs/review-terraform.yaml whose read path has a defaulted workspace parameter.
  • Regenerates zSDKs/terraform-provider-testing. The existing XGlobals resource picks up the same behaviour for its defaulted global fields.

Not a breaking change: imports that include the field produce identical code and state; imports that omit it go from a hard error to the schema default, matching Create and refresh.

Testing

  • ./scripts/build-review-terraform.sh: full regeneration and acceptance suite pass.
  • New TestImportDefaultedIDResourceLifecycle creates the resource with the parameter unset, then imports with only {"id": "..."} and verifies via ImportStateVerify that the default lands in state.
  • make lint, make check-template-terraform, npm run format.
  • Changeset added.

Public-safety check

  • This change contains no credentials, customer documents, private repository URLs, private filesystem paths, or unredacted private logs.
  • Title, body, comments, and commit messages name no customers or customer-derived identifiers, private paths or trackers, or workflow provenance, and are understandable without private context (.claude/skills/public-repo-communication/SKILL.md).
  • Generated fixtures and review SDK changes are public-safe.
  • I reviewed git diff --check.

Summary by cubic

Fixes generated Terraform ImportState so path parameters with a schema default are optional in the JSON import ID, including enum path parameters whose defaults resolve through the enum's underlying type. Importing without a defaulted field now applies the default instead of failing with Missing required field, matching Create and refresh.

  • Defaulted fields are filled with the schema default before being written to state; global fields still use the provider-level value first, and fields without a default keep existing behavior.
  • Adds an ImportDefaultedId review resource with string and enum defaults and an acceptance test that imports with only {"id": "..."} and verifies both defaults land in state.

Written for commit 5dc956d. Summary will update on new commits.

Review in cubic

When a read operation's path parameter has a schema default, the resource
schema already applies it, but the generated ImportState treated the field
as mandatory in the JSON import ID and returned a "Missing required field"
error when it was omitted.

Defaulted fields are now decoded as pointers so absence is distinguishable
from a zero value, and a missing field is filled with the schema default
before being written to state. Global fields keep their provider-level
fallback first. Fields without a default behave as before.

Adds an ImportDefaultedId review resource and an acceptance test that
imports with only the id field and verifies the default lands in state.
@AshGodfrey
AshGodfrey requested a review from a team as a code owner September 15, 2026 10:22
@github-actions github-actions Bot added the terraform Trigger (12) snapshot tests for terraform label Sep 15, 2026
@linear-code

linear-code Bot commented Sep 15, 2026

Copy link
Copy Markdown

TFGEN-321

@cubic-dev-ai

cubic-dev-ai Bot commented Sep 15, 2026

Copy link
Copy Markdown

Running ultrareview automatically — This modifies the core generator template that controls ImportState output, a cross-cutting logic change where a subtle bug in default handling could silently misapply defaults across all generated providers and imported resources.. I'll post findings when complete.

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Ultrareview completed in 11m 19s

2 issues found across 26 files

Confidence score: 3/5

  • zSDKs/terraform-provider-testing/internal/provider/importdefaultedid_resource_sdk.go can replace the imported/schema default for workspace with null when the API omits it, causing later requests to send an empty path segment; preserve the existing r.Workspace unless resp.Workspace is non-null.
  • zSDKs/terraform-provider-testing/examples/resources/testing_import_defaulted_id/import.sh still passes workspace, so the example does not exercise the new omitted-default behavior and may imply the field is required; remove it from the example command.
Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="zSDKs/terraform-provider-testing/examples/resources/testing_import_defaulted_id/import.sh">

<violation number="1" location="zSDKs/terraform-provider-testing/examples/resources/testing_import_defaulted_id/import.sh:1">
P2: This example still supplies `workspace`, so it does not demonstrate the new omitted-default behavior and makes the optional import field look necessary. Remove `workspace` from the example command.</violation>
</file>

<file name="zSDKs/terraform-provider-testing/internal/provider/importdefaultedid_resource_sdk.go">

<violation number="1" location="zSDKs/terraform-provider-testing/internal/provider/importdefaultedid_resource_sdk.go:19">
P1: When the API omits optional `workspace`, this assignment overwrites the imported/schema default with null. The next request sends an empty path segment; preserve the existing `r.Workspace` unless `resp.Workspace` is non-nil.</violation>
</file>

Reply with feedback, questions, or to request a fix.

Fix all with cubic | Re-trigger cubic

if resp != nil {
r.ID = types.StringPointerValue(resp.ID)
r.RequestBodyProperty = types.StringPointerValue(resp.RequestBodyProperty)
r.Workspace = types.StringPointerValue(resp.Workspace)

@cubic-dev-ai cubic-dev-ai Bot Sep 15, 2026

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1: When the API omits optional workspace, this assignment overwrites the imported/schema default with null. The next request sends an empty path segment; preserve the existing r.Workspace unless resp.Workspace is non-nil.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At zSDKs/terraform-provider-testing/internal/provider/importdefaultedid_resource_sdk.go, line 19:

<comment>When the API omits optional `workspace`, this assignment overwrites the imported/schema default with null. The next request sends an empty path segment; preserve the existing `r.Workspace` unless `resp.Workspace` is non-nil.</comment>

<file context>
@@ -0,0 +1,94 @@
+	if resp != nil {
+		r.ID = types.StringPointerValue(resp.ID)
+		r.RequestBodyProperty = types.StringPointerValue(resp.RequestBodyProperty)
+		r.Workspace = types.StringPointerValue(resp.Workspace)
+	}
+
</file context>
Suggested change
r.Workspace = types.StringPointerValue(resp.Workspace)
if resp.Workspace != nil {
r.Workspace = types.StringPointerValue(resp.Workspace)
}
Fix with cubic

Comment thread templates/templates/terraform/includes/generateImportState.ts Outdated
@@ -0,0 +1 @@
terraform import testing_import_defaulted_id.my_testing_import_defaulted_id '{"id": "...", "workspace": "..."}'

@cubic-dev-ai cubic-dev-ai Bot Sep 15, 2026

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2: This example still supplies workspace, so it does not demonstrate the new omitted-default behavior and makes the optional import field look necessary. Remove workspace from the example command.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At zSDKs/terraform-provider-testing/examples/resources/testing_import_defaulted_id/import.sh, line 1:

<comment>This example still supplies `workspace`, so it does not demonstrate the new omitted-default behavior and makes the optional import field look necessary. Remove `workspace` from the example command.</comment>

<file context>
@@ -0,0 +1 @@
+terraform import testing_import_defaulted_id.my_testing_import_defaulted_id '{"id": "...", "workspace": "..."}'
</file context>
Suggested change
terraform import testing_import_defaulted_id.my_testing_import_defaulted_id '{"id": "...", "workspace": "..."}'
terraform import testing_import_defaulted_id.my_testing_import_defaulted_id '{"id": "..."}'
Fix with cubic

Defaulted enum fields fell through the import default literal switch as
undefined, so an enum path parameter with a schema default stayed mandatory in
the JSON import ID and importing without it failed. The literal now resolves
through the enum's underlying type, matching how resource schema defaults are
dispatched.

The review ImportDefaultedId resource gains a defaulted enum path parameter and
the acceptance test verifies both defaults land in state when omitted from the
import ID.
@speakeasy-generator-bot

speakeasy-generator-bot Bot commented Sep 17, 2026

Copy link
Copy Markdown

Generator Snapshot Testing

Selector(s) Result Summary
snapshot-terraform Snapshot run completed

Snapshot results: https://github.com/speakeasy-api/openapi-generation-snapshots/issues/94#issuecomment-5715556185

Snapshot results are summarized above. Additional run context is linked for maintainers with access.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

terraform Trigger (12) snapshot tests for terraform

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant