cloudflare/cloudflared · warning

cloudflared already shutdown

Error message

cloudflared already shutdown

What it means

Returned by Orchestrator.updateIngress when the orchestrator's shutdown channel has already been closed, meaning cloudflared has shut down and no further configuration updates can be applied. It is a lifecycle guard: applying new ingress/warp-routing rules after shutdown is invalid. Callers like UpdateConfig receive this when config reload races shutdown.

Source

Thrown at orchestration/orchestrator.go:153

	if maxActiveFlowsLocalConfig == "" {
		return nil
	}

	maxActiveFlowsLocalOverride, err := strconv.ParseUint(maxActiveFlowsLocalConfig, 10, 64)
	if err != nil {
		return pkgerrors.Wrapf(err, "failed to parse %s", flags.MaxActiveFlows)
	}

	// Override the value that comes from the remote with the local value
	remoteWarpRouting.MaxActiveFlows = maxActiveFlowsLocalOverride
	return nil
}

// The caller is responsible to make sure there is no concurrent access
func (o *Orchestrator) updateIngress(ingressRules ingress.Ingress, warpRouting ingress.WarpRoutingConfig) error {
	select {
	case <-o.shutdownC:
		return fmt.Errorf("cloudflared already shutdown")
	default:
	}

	// Overrides the local values, onto the remote values of the warp routing configuration
	if err := o.overrideRemoteWarpRoutingWithLocalValues(&warpRouting); err != nil {
		return pkgerrors.Wrap(err, "failed to merge local overrides into warp routing configuration")
	}

	// Assign the internal ingress rules to the parsed ingress
	ingressRules.InternalRules = o.internalRules

	// Check if ingress rules are empty, and add the default route if so.
	if ingressRules.IsEmpty() {
		ingressRules.Rules = ingress.GetDefaultIngressRules(o.log)
	}

	// Start new proxy before closing the ones from last version.
	// The upside is we don't need to restart proxy from last version, which can fail

View on GitHub (pinned to 2253eeeb25)

Solutions

  1. Treat the error as benign during shutdown: log at debug/info and abort the update
  2. Check tunnel shutdown state before pushing config updates (e.g. via management APIs that report process state)
  3. Ensure shutdown completes before restart/reload logic issues new updates; serialize updates with the shutdown signal
  4. If seen at startup unexpectedly, investigate an early shutdown (config error or signal) that closed shutdownC before the first update

Example fix

// before
if err := orchestrator.UpdateConfig(config); err != nil {
    return fmt.Errorf("update failed: %w", err)
}
// after
if err := orchestrator.UpdateConfig(config); err != nil {
    if strings.Contains(err.Error(), "already shutdown") {
        log.Debug().Msg("skipping config update: tunnel already shut down")
        return nil
    }
    return fmt.Errorf("update failed: %w", err)
}
Defensive patterns

Strategy: try-catch

Validate before calling

// Go: before pushing a config update, ensure the orchestrator is still running
select {
case <-shutdownC:
    return errors.New("tunnel shutting down; skip config update")
default:
}
err := orchestrator.UpdateConfig(config)

Try / catch

err := orchestrator.UpdateConfig(cfg)
if err != nil {
    if strings.Contains(err.Error(), "cloudflared already shutdown") {
        log.Debug().Msg("config update skipped: orchestrator already shut down")
        return nil
    }
    return err
}

Prevention

When it happens

Trigger: Calling UpdateConfig (remote config change or SIGHUP-triggered reload) after the orchestrator/tunnel has been shut down — e.g. during process teardown, or a config file watcher firing while cloudflared is exiting.

Common situations: SIGTERM/SIGINT delivered while a remote configuration update is in flight; a file-watcher or management-host config push racing process exit; systemd restarting the service with a queued reload; tests that call NewOrchestrator, shut down, then UpdateConfig.

Understand the failure class

Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.

Related errors


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