cloudflare/cloudflared · error

The file-writing error is: %v / The delete tunnel error is:

Error message

The file-writing error is: %v / The delete tunnel error is: %v / The tunnel was deleted, because the tunnel can't be run without the credentials file (joined error lines for failed credentials-file write)

What it means

During Named Tunnel creation, after the tunnel is created remotely, cloudflared writes the credentials file. If BOTH the credentials-file write and the subsequent tunnel-delete cleanup fail, it joins the two error messages plus an explanatory line into a single error, warning that an orphaned tunnel exists that cannot run without its credentials file.

Source

Thrown at cmd/cloudflared/tunnel/subcommand_context.go:186

		credentialsFilePath, err = tunnelFilePath(tunnelCredentials.TunnelID, originCertDir)
		if err != nil {
			return nil, err
		}
		usedCertPath = true
	}
	writeFileErr := writeTunnelCredentials(credentialsFilePath, &tunnelCredentials)
	if writeFileErr != nil {
		var errorLines []string
		errorLines = append(errorLines, fmt.Sprintf("Your tunnel '%v' was created with ID %v. However, cloudflared couldn't write tunnel credentials to %s.", tunnel.Name, tunnel.ID, credentialsFilePath))
		errorLines = append(errorLines, fmt.Sprintf("The file-writing error is: %v", writeFileErr))
		if deleteErr := client.DeleteTunnel(tunnel.ID, true); deleteErr != nil {
			errorLines = append(errorLines, fmt.Sprintf("Cloudflared tried to delete the tunnel for you, but encountered an error. You should use `cloudflared tunnel delete %v` to delete the tunnel yourself, because the tunnel can't be run without the tunnelfile.", tunnel.ID))
			errorLines = append(errorLines, fmt.Sprintf("The delete tunnel error is: %v", deleteErr))
		} else {
			errorLines = append(errorLines, "The tunnel was deleted, because the tunnel can't be run without the credentials file")
		}
		errorMsg := strings.Join(errorLines, "\n")
		return nil, errors.New(errorMsg)
	}

	if outputFormat := sc.c.String(outputFormatFlag.Name); outputFormat != "" {
		return nil, renderOutput(outputFormat, &tunnel)
	}

	fmt.Printf("Tunnel credentials written to %v.", credentialsFilePath)
	if usedCertPath {
		fmt.Print(" cloudflared chose this file based on where your origin certificate was found.")
	}
	fmt.Println(" Keep this file secret. To revoke these credentials, delete the tunnel.")
	fmt.Printf("\nCreated tunnel %s with id %s\n", tunnel.Name, tunnel.ID)

	return &tunnel.Tunnel, nil
}

func (sc *subcommandContext) list(filter *cfapi.TunnelFilter) ([]*cfapi.Tunnel, error) {
	client, err := sc.client()

View on GitHub (pinned to 2253eeeb25)

Solutions

  1. Fix write permissions on the credentials directory: `mkdir -p ~/.cloudflared && chmod u+w ~/.cloudflared`.
  2. Check disk space and quota; free space if full.
  3. Manually delete the orphaned tunnel: `cloudflared tunnel delete <tunnel-ID>`.
  4. Inspect the embedded %v messages in the error for the underlying write and delete causes and address each.

Example fix

// before
$ cloudflared tunnel create mytunnel
// after
$ mkdir -p ~/.cloudflared && chmod u+w ~/.cloudflared
$ cloudflared tunnel create mytunnel
Defensive patterns

Strategy: try-catch

Validate before calling

if [ ! -w "${HOME}/.cloudflared" ] && ! mkdir -p "${HOME}/.cloudflared"; then
  echo "cannot write credentials directory" >&2; exit 1
fi

Try / catch

_, err := createTunnel(ctx)
if err != nil && strings.Contains(err.Error(), "can't be run without the credentials file") {
    // read embedded write/delete causes, fix permissions, then delete orphaned tunnel
}

Prevention

When it happens

Trigger: The directory for the credentials file (default ~/.cloudflared) is not writable or missing, AND the follow-up `cloudflared tunnel delete` also fails (e.g. API/auth error).

Common situations: Read-only home directory; running as wrong user; disk full; expired or missing API token so the cleanup delete is rejected.

Understand the failure class

Background: "failed to write file", "Could not save figure", "Error saving remote file" — file write failed: causes and fixes across languages and libraries — this error's family across 38 libraries.

Related errors


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