Repository: linode/terraform-provider-linode

Issue:
[Bug]: Adding tier on LKE forces replacement
### Terraform Version

v1.7.5 on darwin_arm64

### Linode Provider Version

2.41.0

### Effected Terraform Resources

Adding the `tier` on an existing `linode_lke_cluster` resource forces a replacement, even if the tier matches.

I have an existing LKE cluster (created before LKE-E release). I'm adding tier = 'standard' and it forces a replacement of the whole cluster.   

### Terraform Config Files

_No response_

### Debug Output

_No response_

### Panic Output

_No response_

### Expected Behavior

Tier verified and imported into the state

### Actual Behavior

Resource force-replaced

### Steps to Reproduce

Create `linode_lke_cluster` without tier, then add tier = 'standard'.

Hints from issue comments:
@yec-akamai: @gpietrus-akamai AFAIK, updating the tier is not supported on the API-level. So you can't change the tier value on any existing cluster. Feel free to reopen this issue if you have further question!@gpietrus-akamai: I'm not changing the tier. My cluster is already on standard and I'm adding `tier = standard` to my existing  cluster state. This should NOT trigger a replace.

And I know that I don't need to put `tier = standard`, but since I create some clusters on `tier = enterprise` I'm adapting my code to work for both. 

Anyway, all I'm doing is setting the default tier explicitely. This should NOT trigger a replace. Please reopen this bug.@yec-akamai: @gpietrus-akamai Understood. However, adding the `tier = standard` is considered an Update operation to your existing cluster. There is not allowed on the API level: https://techdocs.akamai.com/linode-api/reference/put-lke-cluster @gpietrus-akamai: How is it an update if it matches the current state? If the API is broken, then please delegate this to the API team, or at least make the Terraform developer-friendly. 

Solution patch:
diff --git a/docs/data-sources/lke_cluster.md b/docs/data-sources/lke_cluster.md
index ba09a989..f6ba5315 100644
--- a/docs/data-sources/lke_cluster.md
+++ b/docs/data-sources/lke_cluster.md
@@ -71,7 +71,7 @@ In addition to all arguments above, the following attributes are exported:
 
   * `tags` - An array of tags applied to this object. Tags are case-insensitive and are for organizational purposes only.
 
-  * `tier` - The desired Kubernetes tier. (**Note: v4beta only and may not currently be available to all users.**)
+  * `tier` - The desired Kubernetes tier. **NOTE: This field may not be available to all users and is only populated when api_version is set to `v4beta`.**
 
   * `k8s_version` - The k8s version of the nodes in this Node Pool. For LKE enterprise only and may not currently available to all users even under v4beta.
 
diff --git a/docs/data-sources/lke_clusters.md b/docs/data-sources/lke_clusters.md
index 1a25fb8c..6bb487b0 100644
--- a/docs/data-sources/lke_clusters.md
+++ b/docs/data-sources/lke_clusters.md
@@ -64,7 +64,7 @@ Each LKE Cluster will be stored in the `lke_clusters` attribute and will export
 
 * `region` - This Kubernetes cluster's location.
 
-* `tier` - The desired Kubernetes tier. (**Note: v4beta only and may not currently be available to all users.**)
+* `tier` - The desired Kubernetes tier. **NOTE: This field may not be available to all users and is only accepted and populated when api_version is set to `v4beta`.**
 
 * `subnet_id` - The ID of the VPC subnet to use for the Kubernetes cluster. This subnet must be dual stack (IPv4 and IPv6 should both be enabled).
 
diff --git a/docs/resources/lke_cluster.md b/docs/resources/lke_cluster.md
index b67eccbb..87c9eed0 100644
--- a/docs/resources/lke_cluster.md
+++ b/docs/resources/lke_cluster.md
@@ -165,9 +165,9 @@ The following arguments are supported:
 
 * `external_pool_tags` - (Optional) A set of node pool tags to ignore when planning and applying this cluster. This prevents externally managed node pools from being deleted or unintentionally updated on subsequent applies. See [Externally Managed Node Pools](#externally-managed-node-pools) for more details.
 
-* `tier` - (Optional) The desired Kubernetes tier. (**Note: v4beta only and may not currently be available to all users.**)
+* `tier` - (Optional) The desired Kubernetes tier. **NOTE: This field may not be available to all users and is only accepted and populated when api_version is set to `v4beta`.**
 
-* `subnet_id` - (Optional) The ID of the VPC subnet to use for the Kubernetes cluster. This subnet must be dual stack (IPv4 and IPv6 should both be enabled). (**Note: v4beta only and may not currently be available to all users.**)
+* `subnet_id` - (Optional) The ID of the VPC subnet to use for the Kubernetes cluster. This subnet must be dual stack (IPv4 and IPv6 should both be enabled). **NOTE: This field may not be available for all users and is only accepted and populated when api_version is set to `v4beta`.**
 
 * `vpc_id` - (Optional) The ID of the VPC to use for the Kubernetes cluster.
 
diff --git a/linode/acceptance/provider_factories.go b/linode/acceptance/provider_factories.go
index e9365051..82a5e6f0 100644
--- a/linode/acceptance/provider_factories.go
+++ b/linode/acceptance/provider_factories.go
@@ -1,6 +1,7 @@
 package acceptance
 
 import (
+	"cmp"
 	"context"
 	"fmt"
 
@@ -9,6 +10,7 @@ import (
 	"github.com/hashicorp/terraform-plugin-go/tfprotov6"
 	"github.com/hashicorp/terraform-plugin-mux/tf5to6server"
 	"github.com/hashicorp/terraform-plugin-mux/tf6muxserver"
+	"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
 	"github.com/hashicorp/terraform-plugin-testing/helper/resource"
 )
 
@@ -48,20 +50,29 @@ var HttpExternalProviders = map[string]resource.ExternalProvider{
 	},
 }
 
-var ProtoV6CustomProviderFactories = map[string]func(provider provider.Provider) (tfprotov6.ProviderServer, error){
-	"linode": func(provider provider.Provider) (tfprotov6.ProviderServer, error) {
+var ProtoV6CustomProviderFactories = map[string]func(
+	provider.Provider,
+	*schema.Provider,
+) (tfprotov6.ProviderServer, error){
+	"linode": func(
+		frameworkProvider provider.Provider,
+		sdkV2Provider *schema.Provider,
+	) (tfprotov6.ProviderServer, error) {
 		ctx := context.Background()
 
+		frameworkProvider = cmp.Or(frameworkProvider, provider.Provider(TestAccFrameworkProvider))
+		sdkV2Provider = cmp.Or(sdkV2Provider, TestAccSDKv2Provider)
+
 		upgradedSDKProvider, err := tf5to6server.UpgradeServer(
 			ctx,
-			TestAccSDKv2Providers["linode"].GRPCProvider,
+			sdkV2Provider.GRPCProvider,
 		)
 		if err != nil {
 			return nil, fmt.Errorf("failed to upgrade SDKv2 GRPC provider: %w", err)
 		}
 
 		providers := []func() tfprotov6.ProviderServer{
-			providerserver.NewProtocol6(provider),
+			providerserver.NewProtocol6(frameworkProvider),
 			func() tfprotov6.ProviderServer { return upgradedSDKProvider },
 		}
 
diff --git a/linode/acceptance/statecheck.go b/linode/acceptance/statecheck.go
new file mode 100644
index 00000000..2e7c844a
--- /dev/null
+++ b/linode/acceptance/statecheck.go
@@ -0,0 +1,31 @@
+package acceptance
+
+import (
+	"context"
+
+	"github.com/hashicorp/terraform-plugin-testing/statecheck"
+)
+
+var _ statecheck.StateCheck = customStateCheck{}
+
+type stateCheckFunc func(
+	context.Context,
+	statecheck.CheckStateRequest,
+	*statecheck.CheckStateResponse,
+)
+
+type customStateCheck struct {
+	inner stateCheckFunc
+}
+
+func (c customStateCheck) CheckState(
+	ctx context.Context,
+	req statecheck.CheckStateRequest,
+	resp *statecheck.CheckStateResponse,
+) {
+	c.inner(ctx, req, resp)
+}
+
+func CustomStateCheck(inner stateCheckFunc) statecheck.StateCheck {
+	return customStateCheck{inner}
+}
diff --git a/linode/acceptance/util.go b/linode/acceptance/util.go
index fc51a71c..32382489 100644
--- a/linode/acceptance/util.go
+++ b/linode/acceptance/util.go
@@ -370,7 +370,10 @@ func CheckListContains(resName, path, value string) resource.TestCheckFunc {
 }
 
 func CheckLKEClusterDestroy(s *terraform.State) error {
-	client := TestAccSDKv2Provider.Meta().(*helper.ProviderMeta).Client
+	client, err := GetTestClient()
+	if err != nil {
+		return err
+	}
 
 	for _, rs := range s.RootModule().Resources {
 		if rs.Type != "linode_lke_cluster" {
@@ -399,7 +402,11 @@ func CheckLKEClusterDestroy(s *terraform.State) error {
 }
 
 func CheckVolumeDestroy(s *terraform.State) error {
-	client := TestAccSDKv2Provider.Meta().(*helper.ProviderMeta).Client
+	client, err := GetTestClient()
+	if err != nil {
+		return err
+	}
+
 	for _, rs := range s.RootModule().Resources {
 		if rs.Type != "linode_volume" {
 			continue
@@ -429,7 +436,10 @@ func CheckVolumeDestroy(s *terraform.State) error {
 
 func CheckVolumeExists(name string, volume *linodego.Volume) resource.TestCheckFunc {
 	return func(s *terraform.State) error {
-		client := TestAccSDKv2Provider.Meta().(*helper.ProviderMeta).Client
+		client, err := GetTestClient()
+		if err != nil {
+			return err
+		}
 
 		rs, ok := s.RootModule().Resources[name]
 		if !ok {
@@ -458,7 +468,10 @@ func CheckVolumeExists(name string, volume *linodego.Volume) resource.TestCheckF
 
 func CheckFirewallExists(name string, firewall *linodego.Firewall) resource.TestCheckFunc {
 	return func(s *terraform.State) error {
-		client := TestAccSDKv2Provider.Meta().(*helper.ProviderMeta).Client
+		client, err := GetTestClient()
+		if err != nil {
+			return err
+		}
 
 		rs, ok := s.RootModule().Resources[name]
 		if !ok {
@@ -487,7 +500,10 @@ func CheckFirewallExists(name string, firewall *linodego.Firewall) resource.Test
 
 func CheckEventAbsent(name string, entityType linodego.EntityType, action linodego.EventAction) resource.TestCheckFunc {
 	return func(s *terraform.State) error {
-		client := TestAccSDKv2Provider.Meta().(*helper.ProviderMeta).Client
+		client, err := GetTestClient()
+		if err != nil {
+			return err
+		}
 
 		rs, ok := s.RootModule().Resources[name]
 		if !ok {
@@ -503,7 +519,7 @@ func CheckEventAbsent(name string, entityType linodego.EntityType, action linode
 			return fmt.Errorf("error parsing %v to int", rs.Primary.ID)
 		}
 
-		event, err := helper.GetLatestEvent(context.Background(), &client, id, entityType, action)
+		event, err := helper.GetLatestEvent(context.Background(), client, id, entityType, action)
 		if err != nil {
 			return err
 		}
@@ -570,9 +586,9 @@ func CreateTestProvider() (*schema.Provider, map[string]*schema.Provider) {
 	return provider, providerMap
 }
 
-type ProviderMetaModifier func(ctx context.Context, config *helper.ProviderMeta) error
+type ProviderMetaModifier func(ctx context.Context, data *schema.ResourceData, config *helper.ProviderMeta) error
 
-func ModifyProviderMeta(provider *schema.Provider, modifier ProviderMetaModifier) {
+func ModifyProviderMeta(provider *schema.Provider, modifier ProviderMetaModifier) *schema.Provider {
 	oldConfigure := provider.ConfigureContextFunc
 
 	provider.ConfigureContextFunc = func(ctx context.Context, data *schema.ResourceData) (interface{}, diag.Diagnostics) {
@@ -581,12 +597,14 @@ func ModifyProviderMeta(provider *schema.Provider, modifier ProviderMetaModifier
 			return nil, err
 		}
 
-		if err := modifier(ctx, config.(*helper.ProviderMeta)); err != nil {
+		if err := modifier(ctx, data, config.(*helper.ProviderMeta)); err != nil {
 			return nil, diag.FromErr(err)
 		}
 
 		return config, nil
 	}
+
+	return provider
 }
 
 func GetEndpointType(e linodego.ObjectStorageEndpoint) string {
diff --git a/linode/helper/constant.go b/linode/helper/constant.go
index 4c7358b9..865037d9 100644
--- a/linode/helper/constant.go
+++ b/linode/helper/constant.go
@@ -1,3 +1,8 @@
 package helper
 
-const TIME_FORMAT = "2006-01-02T15:04:05Z"
+const (
+	TIME_FORMAT = "2006-01-02T15:04:05Z"
+
+	APIVersionV4     = "v4"
+	APIVersionV4Beta = "v4beta"
+)
diff --git a/linode/helper/sdkv2_validators.go b/linode/helper/sdkv2_validators.go
index 9fd83747..2e86507e 100644
--- a/linode/helper/sdkv2_validators.go
+++ b/linode/helper/sdkv2_validators.go
@@ -1,10 +1,14 @@
 package helper
 
 import (
+	"context"
+	"fmt"
 	"net"
+	"strings"
 
 	"github.com/hashicorp/go-cty/cty"
 	"github.com/hashicorp/terraform-plugin-sdk/v2/diag"
+	"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
 )
 
 func SDKv2ValidateIPv4Range(i any, path cty.Path) diag.Diagnostics {
@@ -32,3 +36,39 @@ func SDKv2ValidateIPv6Range(i any, path cty.Path) diag.Diagnostics {
 
 	return nil
 }
+
+// SDKv2ValidateFieldRequiresAPIVersion is an SDKv2 CustomizeDiffFunc
+// that ensures the given fields aren't specified if the configuration API
+// version does not match the required version.
+//
+// NOTE: This needs to be implemented as a CustomizeDiffFunc because it
+// requires access to the provider config.
+func SDKv2ValidateFieldRequiresAPIVersion(
+	requiredAPIVersion string,
+	fieldPaths ...string,
+) schema.CustomizeDiffFunc {
+	return func(ctx context.Context, diff *schema.ResourceDiff, meta any) error {
+		providerMeta := meta.(*ProviderMeta)
+
+		if strings.EqualFold(providerMeta.Config.APIVersion, requiredAPIVersion) {
+			return nil
+		}
+
+		for _, fieldPath := range fieldPaths {
+			_, newValue := diff.GetChange(fieldPath)
+			newValueString := newValue.(string)
+
+			if newValueString == "" {
+				continue
+			}
+
+			return fmt.Errorf(
+				"%s: The api_version provider argument must be set to '%s' to use this field.",
+				fieldPath,
+				requiredAPIVersion,
+			)
+		}
+
+		return nil
+	}
+}
diff --git a/linode/lke/resource.go b/linode/lke/resource.go
index 6159fd47..11be058e 100644
--- a/linode/lke/resource.go
+++ b/linode/lke/resource.go
@@ -42,6 +42,10 @@ func Resource() *schema.Resource {
 			customDiffValidateOptionalCount,
 			linodediffs.ComputedWithDefault("tags", []string{}),
 			linodediffs.CaseInsensitiveSet("tags"),
+			helper.SDKv2ValidateFieldRequiresAPIVersion(
+				helper.APIVersionV4Beta,
+				"tier",
+			),
 		),
 		Timeouts: &schema.ResourceTimeout{
 			Create: schema.DefaultTimeout(createLKETimeout),
diff --git a/linode/lke/schema_resource.go b/linode/lke/schema_resource.go
index 99579dff..0e2be7d8 100644
--- a/linode/lke/schema_resource.go
+++ b/linode/lke/schema_resource.go
@@ -75,8 +75,8 @@ var resourceSchema = map[string]*schema.Schema{
 		Type:        schema.TypeString,
 		Optional:    true,
 		Computed:    true,
-		Description: "The desired Kubernetes tier.",
 		ForceNew:    true,
+		Description: "The desired Kubernetes tier.",
 	},
 	"subnet_id": {
 		Type:        schema.TypeInt,
diff --git a/linode/lke/tmpl/enterprise.gotf b/linode/lke/tmpl/enterprise.gotf
index a2f1e7ef..9c562754 100644
--- a/linode/lke/tmpl/enterprise.gotf
+++ b/linode/lke/tmpl/enterprise.gotf
@@ -35,6 +35,7 @@ resource "linode_lke_cluster" "test" {
         enabled = true
       }
       audit_logs_enabled = true
+      high_availability = true
     }
 }
 
diff --git a/linode/lke/tmpl/template.go b/linode/lke/tmpl/template.go
index 738c7f1f..f15848cd 100644
--- a/linode/lke/tmpl/template.go
+++ b/linode/lke/tmpl/template.go
@@ -25,6 +25,7 @@ type TemplateData struct {
 	Taints           []TaintData
 	Labels           map[string]string
 	AuditLogsEnabled bool
+	Tier             string
 }
 
 func Basic(t testing.TB, name, version, region string) string {
@@ -157,3 +158,10 @@ func ACLDisabledAddressesDisallowed(t testing.TB, name, version, region string)
 		TemplateData{Label: name, K8sVersion: version, Region: region},
 	)
 }
+
+func TierConditional(t testing.TB, name, version, region, tier string) string {
+	return acceptance.ExecuteTemplate(t,
+		"lke_cluster_tier_conditional",
+		TemplateData{Label: name, K8sVersion: version, Region: region, Tier: tier},
+	)
+}
diff --git a/linode/lke/tmpl/tier_conditional.gotf b/linode/lke/tmpl/tier_conditional.gotf
new file mode 100644
index 00000000..0f127f5f
--- /dev/null
+++ b/linode/lke/tmpl/tier_conditional.gotf
@@ -0,0 +1,20 @@
+{{ define "lke_cluster_tier_conditional" }}
+
+resource "linode_lke_cluster" "test" {
+    label       = "{{ .Label }}"
+    region      = "{{ .Region }}"
+    k8s_version = "{{ .K8sVersion }}"
+
+    # Only populate the tier if it's set
+{{ if ne .Tier "" }}
+    tier        = "{{ .Tier }}"
+{{ end }}
+
+    pool {
+        type  = "g6-standard-1"
+        count = 1
+    }
+}
+
+{{ end }}
+



Test patch:
diff --git a/linode/consumerimagesharegroup/datasource_test.go b/linode/consumerimagesharegroup/datasource_test.go
index 12a839f6..861adeb2 100644
--- a/linode/consumerimagesharegroup/datasource_test.go
+++ b/linode/consumerimagesharegroup/datasource_test.go
@@ -52,10 +52,10 @@ func TestAccDataSourceConsumerImageShareGroup_basic(t *testing.T) {
 		PreCheck: func() { acceptance.PreCheck(t) },
 		ProtoV6ProviderFactories: map[string]func() (tfprotov6.ProviderServer, error){
 			"linode-producer": func() (tfprotov6.ProviderServer, error) {
-				return acceptance.ProtoV6CustomProviderFactories["linode"](producerProvider)
+				return acceptance.ProtoV6CustomProviderFactories["linode"](producerProvider, nil)
 			},
 			"linode-consumer": func() (tfprotov6.ProviderServer, error) {
-				return acceptance.ProtoV6CustomProviderFactories["linode"](consumerProvider)
+				return acceptance.ProtoV6CustomProviderFactories["linode"](consumerProvider, nil)
 			},
 		},
 		Steps: []resource.TestStep{
diff --git a/linode/consumerimagesharegroupimageshares/datasource_test.go b/linode/consumerimagesharegroupimageshares/datasource_test.go
index 67036b98..dbe51e8e 100644
--- a/linode/consumerimagesharegroupimageshares/datasource_test.go
+++ b/linode/consumerimagesharegroupimageshares/datasource_test.go
@@ -65,10 +65,10 @@ func TestAccDataSourceImageShareGroupImageShares_basic(t *testing.T) {
 		PreCheck: func() { acceptance.PreCheck(t) },
 		ProtoV6ProviderFactories: map[string]func() (tfprotov6.ProviderServer, error){
 			"linode-producer": func() (tfprotov6.ProviderServer, error) {
-				return acceptance.ProtoV6CustomProviderFactories["linode"](producerProvider)
+				return acceptance.ProtoV6CustomProviderFactories["linode"](producerProvider, nil)
 			},
 			"linode-consumer": func() (tfprotov6.ProviderServer, error) {
-				return acceptance.ProtoV6CustomProviderFactories["linode"](consumerProvider)
+				return acceptance.ProtoV6CustomProviderFactories["linode"](consumerProvider, nil)
 			},
 		},
 		Steps: []resource.TestStep{
diff --git a/linode/consumerimagesharegrouptoken/datasource_test.go b/linode/consumerimagesharegrouptoken/datasource_test.go
index 5ba9564d..99f76851 100644
--- a/linode/consumerimagesharegrouptoken/datasource_test.go
+++ b/linode/consumerimagesharegrouptoken/datasource_test.go
@@ -51,10 +51,10 @@ func TestAccDataSourceImageShareGroupToken_basic(t *testing.T) {
 		PreCheck: func() { acceptance.PreCheck(t) },
 		ProtoV6ProviderFactories: map[string]func() (tfprotov6.ProviderServer, error){
 			"linode-producer": func() (tfprotov6.ProviderServer, error) {
-				return acceptance.ProtoV6CustomProviderFactories["linode"](producerProvider)
+				return acceptance.ProtoV6CustomProviderFactories["linode"](producerProvider, nil)
 			},
 			"linode-consumer": func() (tfprotov6.ProviderServer, error) {
-				return acceptance.ProtoV6CustomProviderFactories["linode"](consumerProvider)
+				return acceptance.ProtoV6CustomProviderFactories["linode"](consumerProvider, nil)
 			},
 		},
 		Steps: []resource.TestStep{
diff --git a/linode/consumerimagesharegrouptoken/resource_test.go b/linode/consumerimagesharegrouptoken/resource_test.go
index 41fafdf5..1b8bd3f4 100644
--- a/linode/consumerimagesharegrouptoken/resource_test.go
+++ b/linode/consumerimagesharegrouptoken/resource_test.go
@@ -52,10 +52,10 @@ func TestAccResourceImageShareGroupToken_basic(t *testing.T) {
 		PreCheck: func() { acceptance.PreCheck(t) },
 		ProtoV6ProviderFactories: map[string]func() (tfprotov6.ProviderServer, error){
 			"linode-producer": func() (tfprotov6.ProviderServer, error) {
-				return acceptance.ProtoV6CustomProviderFactories["linode"](producerProvider)
+				return acceptance.ProtoV6CustomProviderFactories["linode"](producerProvider, nil)
 			},
 			"linode-consumer": func() (tfprotov6.ProviderServer, error) {
-				return acceptance.ProtoV6CustomProviderFactories["linode"](consumerProvider)
+				return acceptance.ProtoV6CustomProviderFactories["linode"](consumerProvider, nil)
 			},
 		},
 		Steps: []resource.TestStep{
diff --git a/linode/consumerimagesharegrouptokens/datasource_test.go b/linode/consumerimagesharegrouptokens/datasource_test.go
index cedd42ff..e407976b 100644
--- a/linode/consumerimagesharegrouptokens/datasource_test.go
+++ b/linode/consumerimagesharegrouptokens/datasource_test.go
@@ -55,10 +55,10 @@ func TestAccDataSourceImageShareGroupTokens_basic(t *testing.T) {
 		PreCheck: func() { acceptance.PreCheck(t) },
 		ProtoV6ProviderFactories: map[string]func() (tfprotov6.ProviderServer, error){
 			"linode-producer": func() (tfprotov6.ProviderServer, error) {
-				return acceptance.ProtoV6CustomProviderFactories["linode"](producerProvider)
+				return acceptance.ProtoV6CustomProviderFactories["linode"](producerProvider, nil)
 			},
 			"linode-consumer": func() (tfprotov6.ProviderServer, error) {
-				return acceptance.ProtoV6CustomProviderFactories["linode"](consumerProvider)
+				return acceptance.ProtoV6CustomProviderFactories["linode"](consumerProvider, nil)
 			},
 		},
 		Steps: []resource.TestStep{
diff --git a/linode/databasemysqlv2/resource_test.go b/linode/databasemysqlv2/resource_test.go
index 48504094..d6c31928 100644
--- a/linode/databasemysqlv2/resource_test.go
+++ b/linode/databasemysqlv2/resource_test.go
@@ -937,7 +937,7 @@ func TestAccResource_noPendingUpdatesRegression(t *testing.T) {
 		PreCheck: func() { acceptance.PreCheck(t) },
 		ProtoV6ProviderFactories: map[string]func() (tfprotov6.ProviderServer, error){
 			"linode": func() (tfprotov6.ProviderServer, error) {
-				return acceptance.ProtoV6CustomProviderFactories["linode"](overriddenProvider)
+				return acceptance.ProtoV6CustomProviderFactories["linode"](overriddenProvider, nil)
 			},
 		},
 		CheckDestroy: acceptance.CheckMySQLDatabaseV2Destroy,
diff --git a/linode/databasepostgresqlv2/resource_test.go b/linode/databasepostgresqlv2/resource_test.go
index 7298091e..45c4cbab 100644
--- a/linode/databasepostgresqlv2/resource_test.go
+++ b/linode/databasepostgresqlv2/resource_test.go
@@ -1029,7 +1029,7 @@ func TestAccResource_noPendingUpdatesRegression(t *testing.T) {
 		PreCheck: func() { acceptance.PreCheck(t) },
 		ProtoV6ProviderFactories: map[string]func() (tfprotov6.ProviderServer, error){
 			"linode": func() (tfprotov6.ProviderServer, error) {
-				return acceptance.ProtoV6CustomProviderFactories["linode"](overriddenProvider)
+				return acceptance.ProtoV6CustomProviderFactories["linode"](overriddenProvider, nil)
 			},
 		},
 		CheckDestroy: acceptance.CheckPostgreSQLDatabaseV2Destroy,
diff --git a/linode/instance/resource_test.go b/linode/instance/resource_test.go
index 713c28f9..658bd628 100644
--- a/linode/instance/resource_test.go
+++ b/linode/instance/resource_test.go
@@ -13,6 +13,7 @@ import (
 	"testing"
 	"time"
 
+	"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
 	"github.com/hashicorp/terraform-plugin-testing/helper/acctest"
 	"github.com/hashicorp/terraform-plugin-testing/helper/resource"
 	"github.com/hashicorp/terraform-plugin-testing/knownvalue"
@@ -2211,7 +2212,7 @@ func TestAccResourceInstance_requestQuantity(t *testing.T) {
 	rootPass := acctest.RandString(64)
 
 	acceptance.ModifyProviderMeta(provider,
-		func(ctx context.Context, config *helper.ProviderMeta) error {
+		func(ctx context.Context, _ *schema.ResourceData, config *helper.ProviderMeta) error {
 			config.Client.OnBeforeRequest(func(request *linodego.Request) error {
 				if startTime.IsZero() {
 					startTime = time.Now()
diff --git a/linode/lke/framework_resource_test.go b/linode/lke/framework_resource_test.go
index 00a8cea6..77e347fc 100644
--- a/linode/lke/framework_resource_test.go
+++ b/linode/lke/framework_resource_test.go
@@ -13,10 +13,16 @@ import (
 	"testing"
 	"time"
 
+	"github.com/hashicorp/terraform-plugin-go/tfprotov6"
+	"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
 	"github.com/hashicorp/terraform-plugin-testing/helper/acctest"
 	"github.com/hashicorp/terraform-plugin-testing/helper/resource"
+	"github.com/hashicorp/terraform-plugin-testing/knownvalue"
+	"github.com/hashicorp/terraform-plugin-testing/statecheck"
 	"github.com/hashicorp/terraform-plugin-testing/terraform"
+	"github.com/hashicorp/terraform-plugin-testing/tfjsonpath"
 	"github.com/linode/linodego"
+	"github.com/linode/terraform-provider-linode/v3/linode"
 	"github.com/linode/terraform-provider-linode/v3/linode/acceptance"
 	"github.com/linode/terraform-provider-linode/v3/linode/helper"
 	"github.com/linode/terraform-provider-linode/v3/linode/lke/tmpl"
@@ -285,7 +291,7 @@ func TestAccResourceLKECluster_basicUpdates(t *testing.T) {
 
 	// We want to ensure that non-updated values are excluded from update requests
 	acceptance.ModifyProviderMeta(provider,
-		func(ctx context.Context, config *helper.ProviderMeta) error {
+		func(ctx context.Context, _ *schema.ResourceData, config *helper.ProviderMeta) error {
 			config.Client.OnBeforeRequest(func(request *linodego.Request) error {
 				if request.Method != "PUT" {
 					return nil
@@ -820,3 +826,117 @@ func TestAccResourceLKECluster_acl_disabled_addresses(t *testing.T) {
 		},
 	})
 }
+
+// TestAccResourceLKECluster_tierNoAccess ensures that a tier value of
+// `standard` will not trigger diffs in a cluster that does not expose
+// the `tier` field due to various circumstances.
+func TestAccResourceLKECluster_tierNoAccess(t *testing.T) {
+	t.Parallel()
+
+	clusterName := acctest.RandomWithPrefix("tf_test")
+
+	apiVersion := "v4"
+
+	apiVersionOverrideProvider := acceptance.ModifyProviderMeta(
+		linode.Provider(),
+		func(ctx context.Context, data *schema.ResourceData, config *helper.ProviderMeta) error {
+			config.Config.APIVersion = apiVersion
+			config.Client.SetAPIVersion(apiVersion)
+
+			return nil
+		},
+	)
+
+	resource.Test(t, resource.TestCase{
+		PreCheck: func() { acceptance.PreCheck(t) },
+		ProtoV6ProviderFactories: map[string]func() (tfprotov6.ProviderServer, error){
+			"linode": func() (tfprotov6.ProviderServer, error) {
+				return acceptance.ProtoV6CustomProviderFactories["linode"](nil, apiVersionOverrideProvider)
+			},
+		},
+		CheckDestroy: acceptance.CheckLKEClusterDestroy,
+		Steps: []resource.TestStep{
+			{
+				Config: tmpl.TierConditional(
+					t,
+					clusterName,
+					k8sVersionLatest,
+					testRegion,
+					string(linodego.LKEVersionStandard),
+				),
+				ExpectError: regexp.MustCompile(
+					"tier: The api_version provider argument must be set to 'v4beta' to use this field\\.",
+				),
+			},
+			{
+				Config: tmpl.TierConditional(
+					t,
+					clusterName,
+					k8sVersionLatest,
+					testRegion,
+					"",
+				),
+				ConfigStateChecks: []statecheck.StateCheck{
+					acceptance.CustomStateCheck(
+						func(
+							ctx context.Context,
+							req statecheck.CheckStateRequest,
+							resp *statecheck.CheckStateResponse,
+						) {
+							if req.State == nil || req.State.Values == nil {
+								resp.Error = fmt.Errorf("invalid state")
+								return
+							}
+
+							for _, resourceEntry := range req.State.Values.RootModule.Resources {
+								if resourceEntry.Type != "linode_lke_cluster" || resourceEntry.Name != "test" {
+									continue
+								}
+
+								tier := resourceEntry.AttributeValues["tier"].(string)
+								if tier != "" {
+									log.Printf(
+										"MAINTAINER ALERT: The tier field is now populated under "+
+											"the v4 API version (value %s). Validation should be removed.\n",
+										tier,
+									)
+								}
+							}
+						},
+					),
+				},
+			},
+			{
+				Config: tmpl.TierConditional(
+					t,
+					clusterName,
+					k8sVersionLatest,
+					testRegion,
+					string(linodego.LKEVersionEnterprise),
+				),
+				ExpectError: regexp.MustCompile(
+					"tier: The api_version provider argument must be set to 'v4beta' to use this field\\.",
+				),
+			},
+			{
+				PreConfig: func() {
+					apiVersion = "v4beta"
+				},
+				Config: tmpl.TierConditional(
+					t,
+					clusterName,
+					k8sVersionLatest,
+					testRegion,
+					string(linodego.LKEVersionStandard),
+				),
+				ConfigStateChecks: []statecheck.StateCheck{
+					statecheck.ExpectKnownValue(
+						"linode_lke_cluster.test",
+						tfjsonpath.New("tier"),
+						knownvalue.StringExact(string(linodego.LKEVersionStandard)),
+					),
+				},
+			},
+		},
+	})
+}
diff --git a/linode/producerimagesharegroupmember/datasource_test.go b/linode/producerimagesharegroupmember/datasource_test.go
index 0e3ab1f3..2b172335 100644
--- a/linode/producerimagesharegroupmember/datasource_test.go
+++ b/linode/producerimagesharegroupmember/datasource_test.go
@@ -52,10 +52,10 @@ func TestAccDataSourceImageShareGroupMember_basic(t *testing.T) {
 		PreCheck: func() { acceptance.PreCheck(t) },
 		ProtoV6ProviderFactories: map[string]func() (tfprotov6.ProviderServer, error){
 			"linode-producer": func() (tfprotov6.ProviderServer, error) {
-				return acceptance.ProtoV6CustomProviderFactories["linode"](producerProvider)
+				return acceptance.ProtoV6CustomProviderFactories["linode"](producerProvider, nil)
 			},
 			"linode-consumer": func() (tfprotov6.ProviderServer, error) {
-				return acceptance.ProtoV6CustomProviderFactories["linode"](consumerProvider)
+				return acceptance.ProtoV6CustomProviderFactories["linode"](consumerProvider, nil)
 			},
 		},
 		Steps: []resource.TestStep{
diff --git a/linode/producerimagesharegroupmember/resource_test.go b/linode/producerimagesharegroupmember/resource_test.go
index 47f79038..65e7daff 100644
--- a/linode/producerimagesharegroupmember/resource_test.go
+++ b/linode/producerimagesharegroupmember/resource_test.go
@@ -53,10 +53,10 @@ func TestAccResourceImageShareGroupMember_basic(t *testing.T) {
 		PreCheck: func() { acceptance.PreCheck(t) },
 		ProtoV6ProviderFactories: map[string]func() (tfprotov6.ProviderServer, error){
 			"linode-producer": func() (tfprotov6.ProviderServer, error) {
-				return acceptance.ProtoV6CustomProviderFactories["linode"](producerProvider)
+				return acceptance.ProtoV6CustomProviderFactories["linode"](producerProvider, nil)
 			},
 			"linode-consumer": func() (tfprotov6.ProviderServer, error) {
-				return acceptance.ProtoV6CustomProviderFactories["linode"](consumerProvider)
+				return acceptance.ProtoV6CustomProviderFactories["linode"](consumerProvider, nil)
 			},
 		},
 		Steps: []resource.TestStep{
diff --git a/linode/producerimagesharegroupmembers/datasource_test.go b/linode/producerimagesharegroupmembers/datasource_test.go
index 79a13022..2464f813 100644
--- a/linode/producerimagesharegroupmembers/datasource_test.go
+++ b/linode/producerimagesharegroupmembers/datasource_test.go
@@ -55,10 +55,10 @@ func TestAccDataSourceImageShareGroupMembers_basic(t *testing.T) {
 		PreCheck: func() { acceptance.PreCheck(t) },
 		ProtoV6ProviderFactories: map[string]func() (tfprotov6.ProviderServer, error){
 			"linode-producer": func() (tfprotov6.ProviderServer, error) {
-				return acceptance.ProtoV6CustomProviderFactories["linode"](producerProvider)
+				return acceptance.ProtoV6CustomProviderFactories["linode"](producerProvider, nil)
 			},
 			"linode-consumer": func() (tfprotov6.ProviderServer, error) {
-				return acceptance.ProtoV6CustomProviderFactories["linode"](consumerProvider)
+				return acceptance.ProtoV6CustomProviderFactories["linode"](consumerProvider, nil)
 			},
 		},
 		Steps: []resource.TestStep{