Over the past few months, I've been working on a project called Liaison. It's a multi-tenant invoicing platform that allows for custom domain configuration and branding. When invoicing a client, it comes from my own domain.

Recently, my friend who's been helping me test Liaison, using his real business, reached out saying that the custom domain that he'd configured was returning a 404. After looking into it, I found a related Sentry error:

Failed to create Cloudflare hostname: Duplicate custom hostname found.

When migrating his account from the legacy system into the new system I manually created a Cloudflare hostname for his business, but I forgot to store the hostname's ID on the custom domain within the Liaison database. While troubleshooting, my friend deleted his custom domain and recreated it which resulted in the error above when the system attempted to create a new custom hostname within Cloudflare.

While this issue would occur pretty rarely and is pretty easy to manually fix, I do think it would be worth solving for it in code. So let's see what we can build with the help of our AI friend, Claude.

When it comes to working with AI coding agents, I've learned that "garbage in = garbage out". To prevent wasting my time on poor solutions, I have a few guidelines I like to follow in order to prevent myself from having to take out the trash.

  1. Fully understand the problem.

  2. Know which files are relevant to the problem.

  3. Understand the possible solutions at a conceptual level.

So, let's get started.

The Problem

If a tenant attempts to add a custom domain and it already exists within Cloudflare, we need to link the existing Cloudflare hostname to the tenant's custom domain.

Relevant Files

  • Exceptions/HostnameProviderException.php

    • The exception that was thrown in Sentry.

  • Actions/AddDomain.php

  • Services/CloudflareHostnameService.php

  • Services/NullHostnameService.php

    • The null service used primarily for testing. We'll need this so that we can replicate the issue in our tests.

  • DomainActionsTest.php

The Solution

When prompting for a plan from Claude Code, I'll be looking to see a modification to the Actions/Domain/AddDomain.php class. This class calls for the creation of the CloudFlare hostname. Prior to this creation call, it should make a call to retrieve a hostname with the same name. If it finds one, it should update the association rather than attempting to create a new one. Additionally, I'll be looking to see tests which properly assert this functionality.

Claude Code Configuration

In the way that I currently use Claude Code, I try to keep my configuration pretty minimally, but it's something that I'm actively experimenting with. But here's a brief overview:

  • My global CLAUDE.md is configured with instructions to ask clarifying questions, to be concise, and to place unresolved questions in plans.

  • My project CLAUDE.md contains Laravel's Boost guidelines plus some details on the Liaison product itself.

  • I've configured relevant MCP servers such as Sentry, which we'll use, and Stripe.

Depending on the problem I'm trying to solve, I may opt to disable MCP servers because I know that they will use up more context than I'd like. So for this specific problem, we won't need to utilize the Stripe MCP server, so it's worth disabling.

The Prompt

The initial prompt will make or break the agent's ability to complete the task accurately. So here's how I typically format it:

# Check for existing Cloudflare Hostname prior to creating a new one

Use the Sentry MCP to view the error 'LIAISON-6' in the 'cadymade' organization. This error was due to a hostname already existing within Cloudflare when a tenant added their custom domain. The error was caused by manual entry within Cloudflare. While this is an edge case, we should still handle it.

### Requirements
- When a new domain is being added and a hostname exists with the provider, associate this new domain with the existing hostname.
- We should modify the AddDomain action to check for an existing hostname and handle the association. If there is a better way to handle this, let me know.
- Write relevant tests which will cover this new functionality.
- Update any relevant tests as needed.
- Ask clarifying questions as necessary.

### Relevant Files
- @app/Exceptions/HostnameProviderException.php
- @app/Actions/AddDomain.php
- @app/Services/CloudflareHostnameService.php
- @app/Services/NullHostnameService.php
- @app/DomainActionsTest.php

Alrighty, so I've pasted this prompt into Claude Code and I'm already benefiting from the agent's extensive training. It suggested a more efficient solution than the one I originally proposed! Let's see it:

# Handle Duplicate Cloudflare Hostnames (LIAISON-6)

## Context
Sentry LIAISON-6: `HostnameProviderException: Failed to create Cloudflare hostname: Duplicate custom hostname found.` — occurs when a hostname was manually added to Cloudflare before the tenant adds it via the app. Edge case but should be handled gracefully.

## Approach: Catch-and-Recover
Try create first. On duplicate error, look up existing hostname and associate it. Avoids extra API call on the happy path and is resilient to race conditions.

## Changes

### 1. New exception: `app/Exceptions/DuplicateHostnameException.php`
- Extends `HostnameProviderException` — marker class, no extra logic

### 2. Add `findHostnameByDomain` to contract + implementations

**`app/Contracts/HostnameProviderContract.php`** — add:
```php
/** @return array{id: string, status: string, ssl_status: string}|null */
public function findHostnameByDomain(string $domain): ?array;
```

**`app/Services/CloudflareHostnameService.php`** — add method:
- GET `zones/{zoneId}/custom_hostnames?hostname={domain}`
- Return first match as `{id, status, ssl_status}` or `null`

Also in `createHostname`: detect "Duplicate custom hostname" error message → throw `DuplicateHostnameException` instead of generic `HostnameProviderException`

**`app/Services/NullHostnameService.php`** — add `findHostnameByDomain` returning `null`

### 3. Update `app/Actions/Domain/AddDomain.php`

Modify `createCloudflareHostname`:
- Catch `DuplicateHostnameException` specifically → call `findHostnameByDomain` → associate
- If lookup also fails, set `status_message`
- Existing generic `HostnameProviderException` catch unchanged

### 4. Tests in `tests/Feature/CloudflareIntegrationTest.php`

Add 3 tests (mocking `HostnameProviderContract`):
1. **Duplicate recovery succeeds** — `createHostname` throws `DuplicateHostnameException`, `findHostnameByDomain` returns existing hostname → assert `cloudflare_hostname_id` set, no `status_message`
2. **Duplicate recovery fails** — both throw/return null → assert `status_message` set, `cloudflare_hostname_id` null
3. **Verification still dispatched on duplicate** — assert `VerifyDomainDns` job dispatched even after duplicate recovery

## Verification
- `php artisan test --filter=CloudflareIntegrationTest`
- `php artisan test --filter=DomainActionsTest`
- `vendor/bin/pint --dirty`

## Unresolved Questions
- Only one CF zone in use? (affects whether `findHostnameByDomain` will always find the duplicate)
- Log info on successful duplicate recovery?

The more efficient change that it's suggesting is via the DuplicateHostnameException path that it's planning to add. Since this bug is an edge case, it doesn't make sense to make two requests to create a tenant's Cloudflare hostname. Instead, it's suggesting that we detect the duplicate hostname error, and then make the request to link the custom domain with the already existing Cloudflare hostname. Working with Claude Code can sometimes be like pairing with another engineer, it suggested this modification that I hadn't yet considered. A true testament to the power of this tool.

Notice that it's also added two unresolved questions to the plan. I'm going to resolve those and then have Claude implement the changes.

Results

In looking at the changes, I'm quite happy with the solution it's written. It's written tests, modified the files I was expecting it to modify and created the DuplicateHostnameException class I wanted.

That being said, there's one larger thing I didn't notice in the plan that I would like to change. It's the error matching logic:

// CloudflareHostnameService.php
if (str_contains($error, 'Duplicate custom hostname')) {
    throw new \App\Exceptions\DuplicateHostnameException("Cloudflare API error: {$error}");
}

When checking the error from Cloudflare, it's running a string comparison on the error message itself. To me, this feels unreliable. What if Cloudflare decides to change the error message? This is a great example of why it is paramount that you check your agent's output. In this example, I'd much rather match using something less ambiguous like a code. Let's see if Cloudflare offers one.

Would you look at that, I've pulled up Cloudflare's API status codes documentation and can see that this error has a status code of 1406. If I set up a Postman call to their API and replicate this error I see the following output:

{
    "result": {
        "ssl": null
    },
    "success": false,
    "errors": [
        {
            "code": 1406,
            "message": "Duplicate custom hostname found."
        }
    ],
    "messages": []
}

There it is. I'll write a follow-up prompt with Claude to update this. We're expecting to see changes to CloudflareHostnameService.php as well as the associated tests.

Here's my follow up prompt. I'm pasting this while Claude is in "Accept Edits" mode rather than plan mode. For a small change like this, I don't think we'll need to go through plan mode again. As a quick note: I learned early on that it's very important to stage these changes prior to running the follow-up. Claude can sometimes go a little nuts, so it's good to be able to revert to your previous state.

@CloudflareHostnameService.php
When detecting the duplicate hostname error, we're running a string comparison. Instead of the string comparison, I'd like to utilize Cloudflare's error codes. For this specific error, the code is 1406. The following JSON structure is what we would expect to see:

```json
{
  "result": {
    "ssl": null
  },
  "success": false,
  "errors": [
    {
      "code": 1406,
      "message": "Duplicate custom hostname found."
    }
  ],
  "messages": []
}
```

Great, our solution has been simplified!

if ($errorCode === 1406) {
    throw new DuplicateHostnameException("Cloudflare API error: {$errorMessage}");
}

This is far more exact, easy to read, and is easier to Google if you need to. At this point the tests, static analysis (PHP Stan), and the linter are all passing. I'm ready to get this out to the world!

Conclusion

When used improperly, these agents can definitely work against you. Even as a solo developer, I typically create PRs so that I can review Claude's code yet again before I commit it to the project. This maintains the review process that I'm already used to at most businesses. Just remember that when it comes to AI, garbage in = garbage out.