Skip to content

Conversation

@agcty
Copy link

@agcty agcty commented Oct 19, 2025

Fixes zone adoption failures when setting values that are already at the desired state.
Previously, adopting an existing zone with default settings (like http2: "on") would fail
with a 400 Bad Request error from Cloudflare's API.

Problem

When adopting an existing Cloudflare zone, updating settings would fail if:

  1. A setting was already at the desired value
  2. Cloudflare's API returned a generic 400 error (not containing "already enabled" text)

This particularly affected settings like http2, http3, ipv6, etc. which default to
"on".

Example error:
Failed to update zone setting http2: Bad Request

Solution

Implemented proper idempotency for zone settings updates:

  1. Fetch current settings first - Query the zone's existing configuration before applying
    updates
  2. Skip unchanged settings - Only update settings that differ from current values
  3. Graceful error handling - Improved 400 error handling to:
    • Parse and log specific error messages
    • Warn instead of throwing for read-only or already-set values
    • Continue processing other settings even if one fails

This follows IaC best practices (similar to Terraform/Pulumi) by:

  • Making zone updates truly idempotent (can run multiple times safely)
  • Reducing unnecessary API calls (performance + rate limit friendly)
  • Providing better error messages for debugging

Testing

Manually tested with real Cloudflare zone containing default settings. Zone adoption now
succeeds and re-running with identical settings is idempotent.

Note: Automated testing is challenging because zone creation requires actual domain
ownership. The existing test suite requires access to .dev domains which need registration
and verification. Future work could improve the test infrastructure for zone resources.

Code snippet

The fix enables this pattern to work reliably:

// First run - adopts existing zone
const zone = await Zone("my-zone", {
  name: "example.com",
  settings: {
    http2: "on",  // Already "on" by default
    ssl: "strict",
  },
});

// Second run - idempotent, no errors
const zone = await Zone("my-zone", {
  name: "example.com",
  settings: {
    http2: "on",  // Skipped (already "on")
    ssl: "strict",
  },
});

// Some settings may be read-only or already in the desired state
if (
data.includes("already enabled") ||
data.includes("cannot be changed")
Copy link
Collaborator

Choose a reason for hiding this comment

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

What settings where causing "cannot be changed"? We need some tests to better test this.

@Mkassabov
Copy link
Collaborator

hey @agcty im a little confused what's happening here. Can you clarify the actual issue and provide a repro where it breaks (even just a gist where you outline what the settings are in the dashboard that can't be properly adopted).

@agcty
Copy link
Author

agcty commented Oct 23, 2025

@Mkassabov Some settings make the creation/update throw, e.g the http2 setting for an already existing zone:

export const zone = await Zone("zone", {
  name: "example.com",
  type: "full",
  delete: false,
  settings: {
    // will error
    http2: "on"
  },
})

Errors with something like can't change setting or something which basically makes the http2 setting unusable, I think alternatively it could also be considered to remove the http2 setting entirely.

@Mkassabov
Copy link
Collaborator

@agcty will take a look at this today and try and repro

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants