@@ -15,6 +15,7 @@ import (
1515 "github.com/hashicorp/terraform-plugin-framework/resource/schema"
1616 "github.com/hashicorp/terraform-plugin-framework/resource/schema/planmodifier"
1717 "github.com/hashicorp/terraform-plugin-framework/resource/schema/stringplanmodifier"
18+ "github.com/hashicorp/terraform-plugin-framework/types"
1819
1920 "github.com/segmentio/public-api-sdk-go/api"
2021)
@@ -144,10 +145,10 @@ func (r *profilesWarehouseResource) Create(ctx context.Context, req resource.Cre
144145 return
145146 }
146147
147- // This is to satisfy terraform requirements that the returned fields must match the input ones because new settings can be generated in the response
148+ // This is to satisfy terraform requirements that the returned fields must match the input ones because new settings can be generated in the response.
148149 state .Settings = plan .Settings
149150
150- // Set state to fully populated data
151+ // Set state to fully populated data.
151152 diags = resp .State .Set (ctx , state )
152153 resp .Diagnostics .Append (diags ... )
153154 if resp .Diagnostics .HasError () {
@@ -238,11 +239,30 @@ func (r *profilesWarehouseResource) Update(ctx context.Context, req resource.Upd
238239 return
239240 }
240241
242+ if (plan .SchemaName .IsNull () || plan .SchemaName .IsUnknown ()) && ! state .SchemaName .IsNull () {
243+ resp .Diagnostics .AddError (
244+ fmt .Sprintf ("Unable to update Profiles Warehouse (ID: %s)" , plan .ID .ValueString ()),
245+ "Cannot unset schema name" ,
246+ )
247+
248+ return
249+ }
250+
251+ // Only send schemaName to API if it differs from the remote state.
252+ // This prevents API failures when the schema name already exists in the warehouse.
253+ // The Segment API fails if we send a schemaName that matches the current configuration.
254+ // even though it should be a no-op. This handles all cases:
255+ // 1. Both null/undefined: Equal() returns true, schemaName stays nil (not sent).
256+ // 2. Both have same value: Equal() returns true, schemaName stays nil (not sent).
257+ // 3. One null, other has value: Equal() returns false, schemaName gets the plan value (sent).
258+ // 4. Both have different values: Equal() returns false, schemaName gets the plan value (sent).
259+ schemaName := determineSchemaNameForUpdate (plan .SchemaName , state .SchemaName )
260+
241261 out , body , err := r .client .ProfilesSyncAPI .UpdateProfilesWarehouseForSpaceWarehouse (r .authContext , state .SpaceID .ValueString (), state .ID .ValueString ()).UpdateProfilesWarehouseForSpaceWarehouseAlphaInput (api.UpdateProfilesWarehouseForSpaceWarehouseAlphaInput {
242262 Enabled : plan .Enabled .ValueBoolPointer (),
243263 Settings : settings ,
244264 Name : plan .Name .ValueStringPointer (),
245- SchemaName : plan . SchemaName . ValueStringPointer () ,
265+ SchemaName : schemaName ,
246266 }).Execute ()
247267 if body != nil {
248268 defer body .Body .Close ()
@@ -268,7 +288,7 @@ func (r *profilesWarehouseResource) Update(ctx context.Context, req resource.Upd
268288 return
269289 }
270290
271- // This is to satisfy terraform requirements that the returned fields must match the input ones because new settings can be generated in the response
291+ // This is to satisfy terraform requirements that the returned fields must match the input ones because new settings can be generated in the response.
272292 state .Settings = plan .Settings
273293
274294 diags = resp .State .Set (ctx , & state )
@@ -362,3 +382,27 @@ func findProfileWarehouse(authContext context.Context, client *api.APIClient, id
362382
363383 return nil , nil
364384}
385+
386+ // determineSchemaNameForUpdate determines whether schemaName should be sent to the API
387+ // based on comparing the plan and state values. This prevents API failures when the
388+ // schema name already exists in the warehouse configuration.
389+ //
390+ // The function returns nil (not sent to API) when:
391+ // - Plan value is unknown (should not send unknown values to API).
392+ // - Plan and state values are equal (no change needed).
393+ //
394+ // The function returns a pointer to the plan value when:
395+ // - Plan and state values are different (legitimate change).
396+ func determineSchemaNameForUpdate (planSchemaName , stateSchemaName types.String ) * string {
397+ // Don't send schemaName to API if plan value is unknown.
398+ if planSchemaName .IsUnknown () {
399+ return nil
400+ }
401+
402+ // Only send schemaName to API if it differs from the remote state.
403+ if ! planSchemaName .Equal (stateSchemaName ) {
404+ return planSchemaName .ValueStringPointer ()
405+ }
406+
407+ return nil
408+ }
0 commit comments