Bug Report: oneuptime_domain Resource - is_verified Field Creation Error #321

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

Originally created by @listellm on 10/30/2025

Summary

The oneuptime_domain resource fails during creation when the is_verified attribute is explicitly set to false. The API returns a 400 error indicating users are not permitted to set the isVerified column.

Environment

  • Terraform Version: >= 1.12.0
  • Provider Version: OneUptime provider >= 8.0.5440, < 9.0.0
  • Resource: oneuptime_domain

API Key Permissions

The API key used for this test was configured with the following permissions:

  • Read Domain - Restriction by labels cannot be applied to this permission
  • Edit Domain - Restriction by labels cannot be applied to this permission
  • Delete Domain - Restriction by labels cannot be applied to this permission
  • Create Domain - Restriction by labels cannot be applied to this permission
  • Project Owner - Restriction by labels cannot be applied to this permission
  • Project Admin - Restriction by labels cannot be applied to this permission

These permissions provide full administrative access to domain resources and the project itself. The error persists despite having the highest level of permissions available.

Issue Description

When attempting to create a domain resource with is_verified = false, the provider sends this field to the API, which rejects the request with the following error:

API request failed with status 400: {"error":"User is not allowed to create on isVerified column of Domain"}

Evidence from OneUptime Web UI

When creating a domain through the OneUptime web interface, the request payload contains only the domain field:

{
  "data": {
    "domain": "example.com"
  },
  "miscDataProps": {}
}

The is_verified field is completely absent from the creation request. This confirms the Terraform provider is incorrectly including a field that should not be sent during resource creation.

Terraform Configuration

resource "oneuptime_domain" "example" {
  project_id  = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
  domain      = "example.com"
  is_verified = false
}

Error Output

Error: Parse Error

  with oneuptime_domain.example,
  on locals.tf line 291, in resource "oneuptime_domain" "example":
 291: resource "oneuptime_domain" "example" {

Unable to parse domain response, got error: API request failed with status
400: {"error":"User is not allowed to create on isVerified column of
Domain"}

Expected Behaviour

The domain should be created successfully. The is_verified field should either:

  1. Be marked as Computed: true, Optional: false in the provider schema (read-only)
  2. Be excluded from the API request payload during resource creation
  3. Default to false on the API side without requiring the client to send it

Actual Behaviour

The provider includes the is_verified field in the creation request, causing the API to reject the request with a 400 error.

Terraform Plan Output

# oneuptime_domain.example will be created
+ resource "oneuptime_domain" "example" {
    + created_at               = (known after apply)
    + created_by_user_id       = (known after apply)
    + deleted_at               = (known after apply)
    + deleted_by_user_id       = (known after apply)
    + domain                   = "example.com"
    + domain_verification_text = (known after apply)
    + id                       = (known after apply)
    + is_verified              = false
    + project_id               = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
    + slug                     = (known after apply)
    + updated_at               = (known after apply)
    + version                  = (known after apply)
  }

Proposed Solution

Modify the provider's oneuptime_domain resource schema to mark is_verified as computed-only:

"is_verified": {
    Type:     schema.TypeBool,
    Computed: true,
    Optional: false,  // Not user-settable
}

Solution 2: Exclude from Create Request

Modify the Create function to explicitly exclude is_verified from the API request payload:

func resourceDomainCreate(d *schema.ResourceData, meta interface{}) error {
    createPayload := map[string]interface{}{
        "data": map[string]interface{}{
            "domain": d.Get("domain").(string),
            // DO NOT include is_verified - it's set by the API after verification
        },
        "miscDataProps": map[string]interface{}{},
    }
    // ... rest of create logic
}

Both solutions are valid, but Solution 1 is cleaner as it makes the field's computed nature explicit in the schema definition.

When attempting to import an existing domain resource, the provider fails to properly deserialize the OneUptime API response format into Terraform state, causing perpetual drift.

Import Configuration

resource "oneuptime_domain" "example" {
  project_id = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
  domain     = "example.com"
}

import {
  to = oneuptime_domain.example
  id = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
}

Import Plan Output

# oneuptime_domain.example will be updated in-place
~ resource "oneuptime_domain" "example" {
    ~ created_at               = jsonencode(
          {
            - _type = "DateTime"
            - value = "2025-10-30T17:23:38.036Z"
          }
      ) -> (known after apply)
    ~ domain                   = jsonencode(
          {
            - _type = "Domain"
            - value = "example.com"
          }
      ) -> "example.com"
    ~ domain_verification_text = "oneuptime-verification-xxxxxxxxxxxx" -> (known after apply)
      id                       = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
    ~ slug                     = "xxxxxxxxxxxx-1234567890" -> (known after apply)
    ~ updated_at               = jsonencode(
          {
            - _type = "DateTime"
            - value = "2025-10-30T17:23:38.036Z"
          }
      ) -> (known after apply)
    ~ version                  = 1 -> (known after apply)
      # (2 unchanged attributes hidden)
  }

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

Root Cause

The OneUptime API returns fields wrapped in JSON objects with _type and value properties:

{
  "_type": "Domain",
  "value": "example.com"
}

The provider's import function stores these wrapped values directly into state using jsonencode() instead of deserializing them to their actual values. This causes Terraform to detect drift even though the actual values haven't changed.

Fields affected:

  • domain: Stored as JSON object instead of plain string
  • created_at: Stored as JSON object instead of timestamp
  • updated_at: Stored as JSON object instead of timestamp
  • Computed fields (slug, version, domain_verification_text) incorrectly marked as changed

Expected Import Behaviour

The import function should deserialize the API response:

// Deserialize wrapped API response values
if domainValue, ok := apiResponse["domain"].(map[string]interface{}); ok {
    d.Set("domain", domainValue["value"])
} else {
    d.Set("domain", apiResponse["domain"])
}

Impact

  • Imported resources cannot achieve stable state
  • Every terraform plan shows spurious changes
  • Imported resources are unusable in Terraform workflows

Workaround

Currently, there is no workaround for either issue:

  1. The resource cannot be created via Terraform due to the is_verified field issue
  2. Existing resources cannot be imported due to the deserialization issue

The domain resource is effectively unusable with the Terraform provider.

Additional Context

  • The is_verified field appears to be a computed value that should only be set by the OneUptime API after domain verification
  • Users should not be able to manually set this field to true during creation
  • The field should be readable after creation to determine verification status

References

*Originally created by @listellm on 10/30/2025* ## Summary The `oneuptime_domain` resource fails during creation when the `is_verified` attribute is explicitly set to `false`. The API returns a 400 error indicating users are not permitted to set the `isVerified` column. ## Environment - **Terraform Version**: >= 1.12.0 - **Provider Version**: OneUptime provider >= 8.0.5440, < 9.0.0 - **Resource**: `oneuptime_domain` ## API Key Permissions The API key used for this test was configured with the following permissions: - **Read Domain** - Restriction by labels cannot be applied to this permission - **Edit Domain** - Restriction by labels cannot be applied to this permission - **Delete Domain** - Restriction by labels cannot be applied to this permission - **Create Domain** - Restriction by labels cannot be applied to this permission - **Project Owner** - Restriction by labels cannot be applied to this permission - **Project Admin** - Restriction by labels cannot be applied to this permission These permissions provide full administrative access to domain resources and the project itself. The error persists despite having the highest level of permissions available. ## Issue Description When attempting to create a domain resource with `is_verified = false`, the provider sends this field to the API, which rejects the request with the following error: ``` API request failed with status 400: {"error":"User is not allowed to create on isVerified column of Domain"} ``` ### Evidence from OneUptime Web UI When creating a domain through the OneUptime web interface, the request payload contains **only** the `domain` field: ```json { "data": { "domain": "example.com" }, "miscDataProps": {} } ``` The `is_verified` field is completely absent from the creation request. This confirms the Terraform provider is incorrectly including a field that should not be sent during resource creation. ## Terraform Configuration ```hcl resource "oneuptime_domain" "example" { project_id = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" domain = "example.com" is_verified = false } ``` ## Error Output ``` Error: Parse Error with oneuptime_domain.example, on locals.tf line 291, in resource "oneuptime_domain" "example": 291: resource "oneuptime_domain" "example" { Unable to parse domain response, got error: API request failed with status 400: {"error":"User is not allowed to create on isVerified column of Domain"} ``` ## Expected Behaviour The domain should be created successfully. The `is_verified` field should either: 1. Be marked as `Computed: true, Optional: false` in the provider schema (read-only) 2. Be excluded from the API request payload during resource creation 3. Default to `false` on the API side without requiring the client to send it ## Actual Behaviour The provider includes the `is_verified` field in the creation request, causing the API to reject the request with a 400 error. ## Terraform Plan Output ``` # oneuptime_domain.example will be created + resource "oneuptime_domain" "example" { + created_at = (known after apply) + created_by_user_id = (known after apply) + deleted_at = (known after apply) + deleted_by_user_id = (known after apply) + domain = "example.com" + domain_verification_text = (known after apply) + id = (known after apply) + is_verified = false + project_id = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" + slug = (known after apply) + updated_at = (known after apply) + version = (known after apply) } ``` ## Proposed Solution ### Solution 1: Mark Field as Computed-Only (Recommended) Modify the provider's `oneuptime_domain` resource schema to mark `is_verified` as computed-only: ```go "is_verified": { Type: schema.TypeBool, Computed: true, Optional: false, // Not user-settable } ``` ### Solution 2: Exclude from Create Request Modify the Create function to explicitly exclude `is_verified` from the API request payload: ```go func resourceDomainCreate(d *schema.ResourceData, meta interface{}) error { createPayload := map[string]interface{}{ "data": map[string]interface{}{ "domain": d.Get("domain").(string), // DO NOT include is_verified - it's set by the API after verification }, "miscDataProps": map[string]interface{}{}, } // ... rest of create logic } ``` Both solutions are valid, but Solution 1 is cleaner as it makes the field's computed nature explicit in the schema definition. ## Related Issue: Import Deserialization Failure When attempting to import an existing domain resource, the provider fails to properly deserialize the OneUptime API response format into Terraform state, causing perpetual drift. ### Import Configuration ```hcl resource "oneuptime_domain" "example" { project_id = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" domain = "example.com" } import { to = oneuptime_domain.example id = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" } ``` ### Import Plan Output ``` # oneuptime_domain.example will be updated in-place ~ resource "oneuptime_domain" "example" { ~ created_at = jsonencode( { - _type = "DateTime" - value = "2025-10-30T17:23:38.036Z" } ) -> (known after apply) ~ domain = jsonencode( { - _type = "Domain" - value = "example.com" } ) -> "example.com" ~ domain_verification_text = "oneuptime-verification-xxxxxxxxxxxx" -> (known after apply) id = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" ~ slug = "xxxxxxxxxxxx-1234567890" -> (known after apply) ~ updated_at = jsonencode( { - _type = "DateTime" - value = "2025-10-30T17:23:38.036Z" } ) -> (known after apply) ~ version = 1 -> (known after apply) # (2 unchanged attributes hidden) } Plan: 0 to add, 1 to change, 0 to destroy. ``` ### Root Cause The OneUptime API returns fields wrapped in JSON objects with `_type` and `value` properties: ```json { "_type": "Domain", "value": "example.com" } ``` The provider's import function stores these wrapped values directly into state using `jsonencode()` instead of deserializing them to their actual values. This causes Terraform to detect drift even though the actual values haven't changed. **Fields affected:** - `domain`: Stored as JSON object instead of plain string - `created_at`: Stored as JSON object instead of timestamp - `updated_at`: Stored as JSON object instead of timestamp - Computed fields (`slug`, `version`, `domain_verification_text`) incorrectly marked as changed ### Expected Import Behaviour The import function should deserialize the API response: ```go // Deserialize wrapped API response values if domainValue, ok := apiResponse["domain"].(map[string]interface{}); ok { d.Set("domain", domainValue["value"]) } else { d.Set("domain", apiResponse["domain"]) } ``` ### Impact - Imported resources cannot achieve stable state - Every `terraform plan` shows spurious changes - Imported resources are unusable in Terraform workflows ## Workaround Currently, there is no workaround for either issue: 1. The resource cannot be created via Terraform due to the `is_verified` field issue 2. Existing resources cannot be imported due to the deserialization issue The domain resource is effectively unusable with the Terraform provider. ## Additional Context - The `is_verified` field appears to be a computed value that should only be set by the OneUptime API after domain verification - Users should not be able to manually set this field to `true` during creation - The field should be readable after creation to determine verification status ## References - OneUptime Terraform Provider: https://registry.terraform.io/providers/OneUptime/oneuptime/latest/docs - Provider Source Code: https://github.com/OneUptime/terraform-provider-oneuptime
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: github/oneuptime#321