Terraform: False 402 License Error on Status Page Update #325

Closed
opened 2026-04-05 16:19:22 +02:00 by MrUnknownDE · 0 comments
Owner

Originally created by @listellm on 10/28/2025

Summary

The OneUptime Terraform provider returns a 402 error ("Please upgrade your plan to Scale to access this feature") when updating a oneuptime_status_page resource, even though the same change can be successfully made through the OneUptime console UI. This suggests the provider is incorrectly triggering a license check or calling the wrong API endpoint.

Expected Behaviour

The Terraform provider should successfully update the status page resource when the underlying API/console allows the operation without license restrictions.

Actual Behaviour

The provider returns a 402 status code with error message: {"error":"Please upgrade your plan to Scale to access this feature"} during the update operation.

Evidence This is a Provider Bug

  • The same change can be successfully completed through the OneUptime console UI
  • No license restrictions are encountered when using the console
  • This indicates the feature itself is not license-restricted, but the Terraform provider is hitting a different/incorrect API endpoint

Steps to Reproduce

  1. Create a oneuptime_status_page resource
  2. Trigger an update that causes Terraform to detect changes (in this case, is_public_status_page changed from false to true)
  3. Run terraform apply
  4. Observe 402 error during update operation

Terraform Configuration

resource "oneuptime_status_page" "this" {
  project_id = var.oneuptime_status_page_project_id
  name       = var.oneuptime_status_page_name
  # Additional configuration omitted for brevity
}

Environment

  • Terraform Version: 1.12.0
  • Provider Version: 8.0.5440
  • Provider Version Constraint: >= 8.0.5440, < 9.0.0
  • Operation: Update existing resource

Terraform Plan Output

Terraform will perform the following actions:

  # module.status_page["organization.project.customer"].oneuptime_status_page.this will be updated in-place
  ~ resource "oneuptime_status_page" "this" {
      + call_sms_config_id                               = (known after apply)
      + copyright_text                                   = (known after apply)
      + cover_image_file_id                              = (known after apply)
      ~ created_at                                       = jsonencode(
            {
              - _type = "DateTime"
              - value = "2025-10-28T17:21:50.068Z"
            }
        ) -> (known after apply)
      ~ created_by_user_id                               = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" -> (known after apply)
      + custom_css                                       = (known after apply)
      + custom_fields                                    = (known after apply)
      + custom_java_script                               = (known after apply)
      + deleted_at                                       = (known after apply)
      + favicon_file_id                                  = (known after apply)
      + footer_html                                      = (known after apply)
      + header_html                                      = (known after apply)
        id                                               = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
      + ip_whitelist                                     = (known after apply)
      ~ is_owner_notified_of_resource_creation           = true -> (known after apply)
      ~ is_public_status_page                            = false -> true
      + logo_file_id                                     = (known after apply)
        name                                             = "example-status-page"
      + overview_page_description                        = (known after apply)
      + page_description                                 = (known after apply)
      + page_title                                       = (known after apply)
      + report_recurring_interval                        = (known after apply)
      + report_start_date_time                           = (known after apply)
      + send_next_report_by                              = (known after apply)
      ~ slug                                             = "example-status-page-1234567890" -> (known after apply)
      + smtp_config_id                                   = (known after apply)
      + subscriber_timezones                             = (known after apply)
      ~ updated_at                                       = jsonencode(
            {
              - _type = "DateTime"
              - value = "2025-10-28T17:22:06.480Z"
            }
        ) -> (known after apply)
      ~ version                                          = 3 -> (known after apply)
        # (27 unchanged attributes hidden)
    }

Plan: 0 to add, 1 to change, 0 to destroy.

Error Output

module.status_page["organization.project.customer"].oneuptime_status_page.this: Modifying... [id=xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx]
╷
│ Error: Parse Error
│
│   with module.status_page["organization.project.customer"].oneuptime_status_page.this,
│   on modules/status_page/main.tf line 6, in resource "oneuptime_status_page" "this":
│    6: resource "oneuptime_status_page" "this" {
│
│ Unable to parse status_page response, got error: API request failed with status 402: {"error":"Please upgrade your plan to Scale to access this feature"}

Possible Root Causes

  1. The provider may be calling a different API endpoint during updates vs what the console uses
  2. The provider may be sending additional parameters that trigger incorrect license validation
  3. The provider may not be properly handling partial updates and attempting to update license-gated fields unnecessarily

Working API Request from Console

When the same change is made successfully through the OneUptime console, the following API request is captured:

Endpoint: PUT https://oneuptime.com/api/status-page/{status-page-id}

Key Headers:

Content-Type: application/json;charset=UTF-8
tenantid: {project-id}
global-permissions-hash: {hash}
project-permissions-hash: {hash}

Payload:

{
  "data": {
    "_id": "{status-page-id}",
    "isPublicStatusPage": true
  },
  "miscDataProps": {}
}

Result: Successful - The API accepts this minimal payload and updates the status page without any license errors.

Root Cause Analysis

The critical difference is in the request payload:

  1. Console UI: Sends a minimal payload containing only:

    • The status page ID
    • The single field being changed (isPublicStatusPage)
    • An empty miscDataProps object
  2. Terraform Provider (suspected): Likely sends the entire resource state including all fields defined in the resource schema, even when most are null or unchanged.

The 402 error suggests:

  • The provider may be sending fields that are only available in paid plans (e.g., hide_powered_by_one_uptime_branding, SMS/Slack subscriber options, SSO requirements)
  • The API incorrectly validates licence entitlements based on the presence of these fields in the request, rather than checking if they're actually being changed or enabled
  • The console avoids this by only sending the specific field(s) being modified

Terraform Module Configuration

For context, our Terraform resource configuration includes 26 configurable attributes (most defaulting to null):

resource "oneuptime_status_page" "this" {
  project_id                                           = var.oneuptime_status_page_project_id
  name                                                 = lower(var.oneuptime_status_page_name)
  description                                          = var.oneuptime_status_page_description
  is_public_status_page                                = var.oneuptime_status_page_is_public_status_page
  enable_email_subscribers                             = var.oneuptime_status_page_enable_email_subscribers
  enable_slack_subscribers                             = var.oneuptime_status_page_enable_slack_subscribers
  enable_sms_subscribers                               = var.oneuptime_status_page_enable_sms_subscribers
  enable_subscribers                                   = var.oneuptime_status_page_enable_subscribers
  allow_subscribers_to_choose_resources                = var.oneuptime_status_page_allow_subscribers_to_choose_resources
  allow_subscribers_to_choose_event_types              = var.oneuptime_status_page_allow_subscribers_to_choose_event_types
  hide_powered_by_one_uptime_branding                  = var.oneuptime_status_page_hide_powered_by_one_uptime_branding
  is_report_enabled                                    = var.oneuptime_status_page_is_report_enabled
  overall_uptime_percent_precision                     = var.oneuptime_status_page_overall_uptime_percent_precision
  report_data_in_days                                  = var.oneuptime_status_page_report_data_in_days
  require_sso_for_login                                = var.oneuptime_status_page_require_sso_for_login
  # ... and more

  lifecycle {
    ignore_changes = [downtime_monitor_statuses]
  }
}

Impact

This bug prevents users from managing status page configuration via Terraform, forcing manual console changes and breaking infrastructure-as-code workflows.

*Originally created by @listellm on 10/28/2025* ## Summary The OneUptime Terraform provider returns a 402 error ("Please upgrade your plan to Scale to access this feature") when updating a `oneuptime_status_page` resource, even though the same change can be successfully made through the OneUptime console UI. This suggests the provider is incorrectly triggering a license check or calling the wrong API endpoint. ## Expected Behaviour The Terraform provider should successfully update the status page resource when the underlying API/console allows the operation without license restrictions. ## Actual Behaviour The provider returns a 402 status code with error message: `{"error":"Please upgrade your plan to Scale to access this feature"}` during the update operation. ## Evidence This is a Provider Bug - The same change can be successfully completed through the OneUptime console UI - No license restrictions are encountered when using the console - This indicates the feature itself is not license-restricted, but the Terraform provider is hitting a different/incorrect API endpoint ## Steps to Reproduce 1. Create a `oneuptime_status_page` resource 2. Trigger an update that causes Terraform to detect changes (in this case, `is_public_status_page` changed from `false` to `true`) 3. Run `terraform apply` 4. Observe 402 error during update operation ## Terraform Configuration ```hcl resource "oneuptime_status_page" "this" { project_id = var.oneuptime_status_page_project_id name = var.oneuptime_status_page_name # Additional configuration omitted for brevity } ``` ## Environment - **Terraform Version**: 1.12.0 - **Provider Version**: 8.0.5440 - **Provider Version Constraint**: `>= 8.0.5440, < 9.0.0` - **Operation**: Update existing resource ## Terraform Plan Output ```text Terraform will perform the following actions: # module.status_page["organization.project.customer"].oneuptime_status_page.this will be updated in-place ~ resource "oneuptime_status_page" "this" { + call_sms_config_id = (known after apply) + copyright_text = (known after apply) + cover_image_file_id = (known after apply) ~ created_at = jsonencode( { - _type = "DateTime" - value = "2025-10-28T17:21:50.068Z" } ) -> (known after apply) ~ created_by_user_id = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" -> (known after apply) + custom_css = (known after apply) + custom_fields = (known after apply) + custom_java_script = (known after apply) + deleted_at = (known after apply) + favicon_file_id = (known after apply) + footer_html = (known after apply) + header_html = (known after apply) id = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" + ip_whitelist = (known after apply) ~ is_owner_notified_of_resource_creation = true -> (known after apply) ~ is_public_status_page = false -> true + logo_file_id = (known after apply) name = "example-status-page" + overview_page_description = (known after apply) + page_description = (known after apply) + page_title = (known after apply) + report_recurring_interval = (known after apply) + report_start_date_time = (known after apply) + send_next_report_by = (known after apply) ~ slug = "example-status-page-1234567890" -> (known after apply) + smtp_config_id = (known after apply) + subscriber_timezones = (known after apply) ~ updated_at = jsonencode( { - _type = "DateTime" - value = "2025-10-28T17:22:06.480Z" } ) -> (known after apply) ~ version = 3 -> (known after apply) # (27 unchanged attributes hidden) } Plan: 0 to add, 1 to change, 0 to destroy. ``` ## Error Output ```text module.status_page["organization.project.customer"].oneuptime_status_page.this: Modifying... [id=xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx] ╷ │ Error: Parse Error │ │ with module.status_page["organization.project.customer"].oneuptime_status_page.this, │ on modules/status_page/main.tf line 6, in resource "oneuptime_status_page" "this": │ 6: resource "oneuptime_status_page" "this" { │ │ Unable to parse status_page response, got error: API request failed with status 402: {"error":"Please upgrade your plan to Scale to access this feature"} ``` ## Possible Root Causes 1. The provider may be calling a different API endpoint during updates vs what the console uses 2. The provider may be sending additional parameters that trigger incorrect license validation 3. The provider may not be properly handling partial updates and attempting to update license-gated fields unnecessarily ## Working API Request from Console When the same change is made successfully through the OneUptime console, the following API request is captured: **Endpoint**: `PUT https://oneuptime.com/api/status-page/{status-page-id}` **Key Headers**: ```text Content-Type: application/json;charset=UTF-8 tenantid: {project-id} global-permissions-hash: {hash} project-permissions-hash: {hash} ``` **Payload**: ```json { "data": { "_id": "{status-page-id}", "isPublicStatusPage": true }, "miscDataProps": {} } ``` **Result**: ✅ **Successful** - The API accepts this minimal payload and updates the status page without any license errors. ## Root Cause Analysis The critical difference is in the request payload: 1. **Console UI**: Sends a minimal payload containing only: - The status page ID - The single field being changed (`isPublicStatusPage`) - An empty `miscDataProps` object 2. **Terraform Provider** (suspected): Likely sends the entire resource state including all fields defined in the resource schema, even when most are null or unchanged. **The 402 error suggests**: - The provider may be sending fields that are only available in paid plans (e.g., `hide_powered_by_one_uptime_branding`, SMS/Slack subscriber options, SSO requirements) - The API incorrectly validates licence entitlements based on the presence of these fields in the request, rather than checking if they're actually being changed or enabled - The console avoids this by only sending the specific field(s) being modified ## Terraform Module Configuration For context, our Terraform resource configuration includes 26 configurable attributes (most defaulting to `null`): ```hcl resource "oneuptime_status_page" "this" { project_id = var.oneuptime_status_page_project_id name = lower(var.oneuptime_status_page_name) description = var.oneuptime_status_page_description is_public_status_page = var.oneuptime_status_page_is_public_status_page enable_email_subscribers = var.oneuptime_status_page_enable_email_subscribers enable_slack_subscribers = var.oneuptime_status_page_enable_slack_subscribers enable_sms_subscribers = var.oneuptime_status_page_enable_sms_subscribers enable_subscribers = var.oneuptime_status_page_enable_subscribers allow_subscribers_to_choose_resources = var.oneuptime_status_page_allow_subscribers_to_choose_resources allow_subscribers_to_choose_event_types = var.oneuptime_status_page_allow_subscribers_to_choose_event_types hide_powered_by_one_uptime_branding = var.oneuptime_status_page_hide_powered_by_one_uptime_branding is_report_enabled = var.oneuptime_status_page_is_report_enabled overall_uptime_percent_precision = var.oneuptime_status_page_overall_uptime_percent_precision report_data_in_days = var.oneuptime_status_page_report_data_in_days require_sso_for_login = var.oneuptime_status_page_require_sso_for_login # ... and more lifecycle { ignore_changes = [downtime_monitor_statuses] } } ``` ## Impact This bug prevents users from managing status page configuration via Terraform, forcing manual console changes and breaking infrastructure-as-code workflows.
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: github/oneuptime#325