{"record":{"id":"d87158c839061a39","repo":"cloudflare/cloudflared","slug":"errtunnelnameconflict","errorCode":"ErrTunnelNameConflict","errorMessage":"tunnel with name already exists","messagePattern":"tunnel with name already exists","errorType":"error_code","errorClass":null,"httpStatus":null,"severity":"error","filePath":"cfapi/tunnel.go","lineNumber":16,"sourceCode":"package cfapi\n\nimport (\n\t\"fmt\"\n\t\"io\"\n\t\"net\"\n\t\"net/http\"\n\t\"net/url\"\n\t\"path\"\n\t\"time\"\n\n\t\"github.com/google/uuid\"\n\t\"github.com/pkg/errors\"\n)\n\nvar ErrTunnelNameConflict = errors.New(\"tunnel with name already exists\")\n\ntype ManagementResource int\n\nconst (\n\tLogs ManagementResource = iota\n\tAdmin\n\tHostDetails\n)\n\nfunc (r ManagementResource) String() string {\n\tswitch r {\n\tcase Logs:\n\t\treturn \"logs\"\n\tcase Admin:\n\t\treturn \"admin\"\n\tcase HostDetails:\n\t\treturn \"host_details\"\n\tdefault:","sourceCodeStart":1,"sourceCodeEnd":34,"githubUrl":"https://github.com/cloudflare/cloudflared/blob/2253eeeb25a44a713a4b60b8ba1e1b3f377d1a0f/cfapi/tunnel.go#L1-L34","documentation":"ErrTunnelNameConflict is returned by CreateTunnel when the Cloudflare API responds with HTTP 409 Conflict, meaning a tunnel with the same name already exists in the account. Tunnel names must be unique per account, so creating a duplicate is rejected. It is a package-level sentinel usable with errors.Is.","triggerScenarios":"Calling RESTClient.CreateTunnel with a name that already exists for another tunnel in the same Cloudflare account, or re-running a provisioning script without deleting the previously created tunnel.","commonSituations":"Idempotency mistakes in CI/CD tunnel provisioning; leftover tunnels from failed deployments; two pipeline jobs racing to create the same named tunnel; migrating scripts that assume fresh accounts.","solutions":["List existing tunnels first and reuse the existing tunnel ID instead of creating a new one","Choose a unique tunnel name (e.g. include an environment or run identifier)","Delete the stale tunnel before recreating, or use `cloudflared tunnel cleanup`","Handle the sentinel with errors.Is(err, cfapi.ErrTunnelNameConflict) and treat as success if the existing tunnel is the intended one"],"exampleFix":"// before\ntunnel, err := client.CreateTunnel(name, secret)\nif err != nil {\n    return err\n}\n// after\ntunnel, err := client.CreateTunnel(name, secret)\nif errors.Is(err, cfapi.ErrTunnelNameConflict) {\n    tunnel, err = client.GetTunnelByName(ctx, accountTag, name)\n    if err != nil {\n        return err\n    }\n} else if err != nil {\n    return err\n}","handlingStrategy":"validation","validationCode":"names, err := client.ListTunnelNames(ctx, accountTag)\nif err != nil { return err }\nfor _, n := range names {\n    if n == desiredName { /* reuse existing tunnel */ }\n}","typeGuard":"func isNameConflict(err error) bool { return errors.Is(err, cfapi.ErrTunnelNameConflict) }","tryCatchPattern":"t, err := client.CreateTunnel(name, secret)\nif errors.Is(err, cfapi.ErrTunnelNameConflict) {\n    t, err = client.GetTunnelByName(ctx, accountTag, name) // fall back to existing\n}","preventionTips":["Check for an existing tunnel with the same name before creating","Make provisioning scripts idempotent (create-or-get)","Namespace tunnel names per environment/pipeline run","Serialize creation steps to avoid two jobs racing"],"tags":["api","cloudflare","conflict","tunnel"],"backgroundTag":"resource-already-exists","analyzedSha":"2253eeeb25a44a713a4b60b8ba1e1b3f377d1a0f","analyzedAt":"2026-09-06T04:14:33.757Z","contentChangedAt":"2026-09-06T04:14:33.757Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}