cloudflare/cloudflared · error
configuration file %s must contain entries for the tunnel to
Error message
configuration file %s must contain entries for the tunnel to run and its associated credentials (tunnel: TUNNEL-UUID, credentials-file: CREDENTIALS-FILE)
What it means
Thrown by buildArgsForConfig in cmd/cloudflared/linux_service.go when installing cloudflared as a Linux service. Before the service can run autonomously, the config file must name the tunnel (TunnelID) and its credentials file (credentials-file). If either entry is missing or empty, service installation is aborted because the systemd/OpenRC unit would launch a tunnel it cannot identify or authenticate.
Source
Thrown at cmd/cloudflared/linux_service.go:332
}
func buildArgsForConfig(c *cli.Context, log *zerolog.Logger) ([]string, error) {
if err := ensureConfigDirExists(serviceConfigDir); err != nil {
return nil, err
}
src, _, err := config.ReadConfigFile(c, log)
if err != nil {
return nil, err
}
// can't use context because this command doesn't define "credentials-file" flag
configPresent := func(s string) bool {
val, err := src.String(s)
return err == nil && val != ""
}
if src.TunnelID == "" || !configPresent(tunnel.CredFileFlag) {
return nil, fmt.Errorf("configuration file %s must contain entries for the tunnel to run and its associated credentials (tunnel: TUNNEL-UUID, credentials-file: CREDENTIALS-FILE)", src.Source())
}
if src.Source() != serviceConfigPath {
if exists, err := config.FileExists(serviceConfigPath); err != nil || exists {
return nil, fmt.Errorf("possible conflicting configuration in %[1]s and %[2]s. Either remove %[2]s or run `cloudflared --config %[2]s service install`", src.Source(), serviceConfigPath)
}
if err := copyFile(src.Source(), serviceConfigPath); err != nil {
return nil, fmt.Errorf("failed to copy %s to %s: %w", src.Source(), serviceConfigPath, err)
}
}
return []string{
"--config", "/etc/cloudflared/config.yml", "tunnel", "run",
}, nil
}
func installSystemd(templateArgs *ServiceTemplateArgs, autoUpdate bool, log *zerolog.Logger) error {
var systemdTemplates []ServiceTemplateView on GitHub (pinned to 2253eeeb25)
Solutions
- Add `tunnel: <TUNNEL-UUID>` and `credentials-file: /path/to/<UUID>.json` to the config file passed to `cloudflared service install`.
- Alternatively install with a token: `cloudflared service install <TOKEN>` for remotely-managed tunnels.
- Verify the config file being picked up (check the path in the error message) — use `cloudflared --config /path/config.yml tunnel ingress validate` to confirm entries parse.
- Re-run `cloudflared --config /path/config.yml service install` after fixing the file.
Example fix
// before: config.yml // ingress: // - hostname: app.example.com // service: http://localhost:8080 // after: config.yml // tunnel: 6ff42ae2-765d-4adf-8336-94d036a6e840 // credentials-file: /etc/cloudflared/6ff42ae2-765d-4adf-8336-94d036a6e840.json // ingress: // - hostname: app.example.com // service: http://localhost:8080
Defensive patterns
Strategy: validation
Validate before calling
// Go: validate config before service install
cfg, err := config.LoadConfig(configPath)
if err != nil {
return err
}
if cfg.TunnelID == "" {
return fmt.Errorf("config %s is missing 'tunnel:' entry required for service install", configPath)
}
if cfg.CredFileFlag == "" || !config.FileExists(cfg.CredFileFlag) {
return fmt.Errorf("config %s is missing a valid 'credentials-file:' entry", configPath)
} Try / catch
// Go
cmd := exec.Command("cloudflared", "--config", configPath, "service", "install")
out, err := cmd.CombinedOutput()
if err != nil && strings.Contains(string(out), "must contain entries for the tunnel") {
// add tunnel/credentials-file keys to the config or use token-based install
return fmt.Errorf("config incomplete for service install: %s", out)
} Prevention
- Always include both `tunnel:` and `credentials-file:` keys in any config destined for service install
- Run `cloudflared tunnel ingress validate --config <file>` before installing the service
- Prefer token-based installs (`cloudflared service install <TOKEN>`) for remotely-managed tunnels
- Keep a canonical /etc/cloudflared/config.yml and edit it directly rather than passing ad-hoc configs
When it happens
Trigger: Running `cloudflared service install` where the effective config source (flag --config file or token-based config) has src.TunnelID == "" or no non-empty value for tunnel.CredFileFlag. Typical when the config file lacks `tunnel:` and/or `credentials-file:` keys, or only `ingress:` rules are present.
Common situations: Users write a config with only ingress rules and try to install it as a service; migrating from `cloudflared tunnel run` (flag-based) to service install without adding tunnel/credentials-file keys; copying an example config that omits credentials; using a remotely-managed tunnel token but an incomplete local config file.
Understand the failure class
Background: "is required", "must be set", "missing required field": configuration validation errors across open-source libraries — this error's family across 36 libraries.
Related errors
- possible conflicting configuration in %[1]s and %[2]s. Eithe
- use `cloudflared tunnel run` to start tunnel %s
- ErrNoTunnelID
- ErrInvalidTunnelID
- errDeprecatedClassicTunnel
AI-assisted analysis of cloudflare/cloudflared@2253eeeb25 (2026-09-06).
Data as JSON: /api/errors/2c8b8e1e588e280c.
Report an issue: GitHub.