cloudflare/cloudflared · error

Couldn't decode tunnel secret from base64

Error message

Couldn't decode tunnel secret from base64

What it means

When a tunnel secret is supplied via --secret, create() decodes it from base64; if base64.StdEncoding.DecodeString fails, this wrapped error is returned. The secret must be valid standard-base64 and at least 32 bytes once decoded.

Source

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

	return credentials, nil
}

func (sc *subcommandContext) create(name string, credentialsFilePath string, secret string) (*cfapi.Tunnel, error) {
	client, err := sc.client()
	if err != nil {
		return nil, errors.Wrap(err, "couldn't create client to talk to Cloudflare Tunnel backend")
	}

	var tunnelSecret []byte
	if secret == "" {
		tunnelSecret, err = generateTunnelSecret()
		if err != nil {
			return nil, errors.Wrap(err, "couldn't generate the secret for your new tunnel")
		}
	} else {
		decodedSecret, err := base64.StdEncoding.DecodeString(secret)
		if err != nil {
			return nil, errors.Wrap(err, "Couldn't decode tunnel secret from base64")
		}
		tunnelSecret = decodedSecret
		if len(tunnelSecret) < 32 {
			return nil, errors.New("Decoded tunnel secret must be at least 32 bytes long")
		}
	}

	tunnel, err := client.CreateTunnel(name, tunnelSecret)
	if err != nil {
		return nil, errors.Wrap(err, "Create Tunnel API call failed")
	}

	credential, err := sc.credential()
	if err != nil {
		return nil, err
	}

	tunnelCredentials := connection.Credentials{

View on GitHub (pinned to 2253eeeb25)

Solutions

  1. Regenerate the secret as standard base64 of >=32 random bytes: `head -c 32 /dev/urandom | base64`
  2. Quote the secret in the shell to avoid character mangling
  3. If the value uses URL-safe base64, convert it (replace -/_, restore padding) to standard base64
  4. Ensure no trailing newline/whitespace is included (e.g. strip with tr -d '\n')

Example fix

// before
cloudflared tunnel create --secret "abc-123_xyz" mytunnel
// after
SECRET=$(head -c 32 /dev/urandom | base64)
cloudflared tunnel create --secret "$SECRET" mytunnel
Defensive patterns

Strategy: validation

Validate before calling

decoded, err := base64.StdEncoding.DecodeString(secret)
if err != nil {
    return fmt.Errorf("--secret must be standard base64: %w", err)
}
if len(decoded) < 32 {
    return fmt.Errorf("--secret must decode to at least 32 bytes, got %d", len(decoded))
}

Prevention

When it happens

Trigger: `cloudflared tunnel create --secret <value>` where <value> contains characters outside the standard base64 alphabet or wrong padding.

Common situations: Passing a URL-safe base64 string (with - and _) instead of standard base64; trailing whitespace/newlines; shell mangling of special characters; reusing a raw hex or plaintext string as the secret.

Understand the failure class

Background: "Invalid ... format", "must be in format X", "does not look like a ..." — invalid argument format errors across CLI tools and libraries — this error's family across 17 libraries.

Related errors


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