cloudflare/cloudflared · error

failed to create tunnel

Error message

failed to create tunnel

What it means

runAdhocNamedTunnel creates a named tunnel via the Cloudflare API when no active tunnel with that name exists; if sc.create() fails (any Tunnelstore/API error: auth, network, name conflict, quota) the error is wrapped as 'failed to create tunnel'. The secret is passed as an empty string so the API generates one, meaning failures are on the create call itself, not secret handling.

Source

Thrown at cmd/cloudflared/tunnel/cmd.go:284

	if c.String("hostname") != "" {
		return errDeprecatedClassicTunnel
	}

	return errors.New(tunnelCmdErrorMessage)
}

func Init(info *cliutil.BuildInfo, gracefulShutdown chan struct{}) {
	buildInfo, graceShutdownC = info, gracefulShutdown
}

// runAdhocNamedTunnel create, route and run a named tunnel in one command
func runAdhocNamedTunnel(sc *subcommandContext, name, credentialsOutputPath string) error {
	tunnel, ok, err := sc.tunnelActive(name)
	if err != nil || !ok {
		// pass empty string as secret to generate one
		tunnel, err = sc.create(name, credentialsOutputPath, "")
		if err != nil {
			return errors.Wrap(err, "failed to create tunnel")
		}
	} else {
		sc.log.Info().Str(LogFieldTunnelID, tunnel.ID.String()).Msg("Reusing existing tunnel with this name")
	}

	if r, ok := routeFromFlag(sc.c); ok {
		if res, err := sc.route(tunnel.ID, r); err != nil {
			sc.log.Err(err).Str("route", r.String()).Msg(routeFailMsg)
		} else {
			sc.log.Info().Msg(res.SuccessSummary())
		}
	}

	if err := sc.run(tunnel.ID); err != nil {
		return errors.Wrap(err, "error running tunnel")
	}

	return nil

View on GitHub (pinned to 2253eeeb25)

Solutions

  1. Run `cloudflared tunnel login` (or provide TUNNEL_TOKEN) to establish valid credentials, then retry.
  2. Check network connectivity to api.cloudflare.com and any proxy/firewall rules.
  3. Read the wrapped inner error above this message for the specific API failure (401/403 vs 5xx vs file error).
  4. If the name conflicts, pick a different tunnel name or delete the old tunnel via `cloudflared tunnel delete <name>`.
  5. Verify the account has quota and the cert.pem in ~/.cloudflared belongs to the right account.

Example fix

// before
cloudflared tunnel run --name mytunnel   # fails: not logged in

// after
cloudflared tunnel login
cloudflared tunnel run --name mytunnel
Defensive patterns

Strategy: try-catch

Validate before calling

# before running
test -f ~/.cloudflared/cert.pem || cloudflared tunnel login
curl -sS -o /dev/null https://api.cloudflare.com || echo "no egress to Cloudflare API"

Try / catch

if err := runTunnelCmd(); err != nil {
    if strings.Contains(err.Error(), "failed to create tunnel") {
        log.Errorf("tunnel create failed: %v — check cert.pem / API access", err)
    }
}

Prevention

When it happens

Trigger: `cloudflared tunnel run --name <name>` (or `tunnel create` ad-hoc path) where sc.tunnelActive either errored or found nothing and sc.create(name, credentialsOutputPath, "") then fails: expired/missing origin cert or token, Tunnelstore API 4xx/5xx, network outage, tunnel-name already used but deleted filter mismatch, or credentials-output path unwritable.

Common situations: Not logged in (`cloudflared tunnel login` never run) so cert.pem is missing; stale cert.pem after account change; offline/blocked network to api.cloudflare.com; running under a token-less service install where cert is absent; hitting the account's tunnel limit.

Understand the failure class

Background: "API request failed": what wrapped HTTP errors from external APIs mean and how to find the real cause — this error's family across 29 libraries.

Related errors


AI-assisted analysis of cloudflare/cloudflared@2253eeeb25 (2026-09-06). Data as JSON: /api/errors/0fae24c14583daf3. Report an issue: GitHub.