{"record":{"id":"b275823bf114a1c9","repo":"hashicorp/nomad","slug":"client-stopped-and-may-not-longer-create-config-en","errorCode":null,"errorMessage":"client stopped and may not longer create config entries","messagePattern":"client stopped and may not longer create config entries","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"nomad/consul.go","lineNumber":102,"sourceCode":"func (c *consulConfigsAPI) SetIngressCE(ctx context.Context, namespace, service, cluster, partition string, entry *structs.ConsulIngressConfigEntry) error {\n\treturn c.setCE(ctx, convertIngressCE(namespace, service, entry), cluster, partition)\n}\n\nfunc (c *consulConfigsAPI) SetTerminatingCE(ctx context.Context, namespace, service, cluster, partition string, entry *structs.ConsulTerminatingConfigEntry) error {\n\treturn c.setCE(ctx, convertTerminatingCE(namespace, service, entry), cluster, partition)\n}\n\n// setCE will set the Configuration Entry of any type Consul supports.\nfunc (c *consulConfigsAPI) setCE(ctx context.Context, entry api.ConfigEntry, cluster, partition string) error {\n\tdefer metrics.MeasureSince([]string{\"nomad\", \"consul\", \"create_config_entry\"}, time.Now())\n\n\t// make sure the background deletion goroutine has not been stopped\n\tc.lock.Lock()\n\tstopped := c.stopped\n\tc.lock.Unlock()\n\n\tif stopped {\n\t\treturn errors.New(\"client stopped and may not longer create config entries\")\n\t}\n\n\t// ensure we are under our wait limit\n\tif err := c.limiter.Wait(ctx); err != nil {\n\t\treturn err\n\t}\n\n\tclient := c.configsClientFunc(cluster)\n\t_, _, err := client.Set(entry, &api.WriteOptions{\n\t\tNamespace: entry.GetNamespace(),\n\t\tPartition: partition,\n\t})\n\treturn err\n}\n\nfunc convertIngressCE(namespace, service string, entry *structs.ConsulIngressConfigEntry) api.ConfigEntry {\n\tvar listeners []api.IngressListener = nil\n\tfor _, listener := range entry.Listeners {","sourceCodeStart":84,"sourceCodeEnd":120,"githubUrl":"https://github.com/hashicorp/nomad/blob/482b49bf1aec006f089bcfc7e632d8f6ac303e5e/nomad/consul.go#L84-L120","documentation":"Nomad's Consul config-entry wrapper (setCE) guards writes with a stopped flag. Once the background deletion goroutine has been shut down, any attempt to create a Consul config entry (ingress/terminating-gateway) returns this error instead of racing a dead worker. The typo 'may not longer' is in the original message.","triggerScenarios":"Calling SetIngressCE or SetTerminatingCE after the client's consul config-entry deletion goroutine was stopped during Nomad shutdown; a config-entry write racing server shutdown.","commonSituations":"Ingress/terminating-gateway config entries being applied while the Nomad server is shutting down or being restarted; tests or scripts pushing config entries at shutdown time.","solutions":["Retry the operation after Nomad restarts and the consul client is re-initialized","Ensure config-entry writes are issued while the server is healthy, not during shutdown","Check server logs for the shutdown sequence to confirm this was a race with process exit","If seen persistently while the server is up, investigate why the deletion goroutine stopped early (bug report)"],"exampleFix":"// before\nerr := consulClient.SetIngressCE(ctx, service, namespace, gateway, config)\n// after: check server health before writing\nif err := apiClient.Agent().HealthChecks...; nomadRunning {\n    err = consulClient.SetIngressCE(ctx, service, namespace, gateway, config)\n}","handlingStrategy":"retry","validationCode":"// before writing config entries, ensure nomad is not shutting down\nif serverShuttingDown() { return fmt.Errorf(\"defer config entry write\") }","typeGuard":null,"tryCatchPattern":"// Go\nif err := c.SetIngressCE(ctx, svc, ns, gw, cfg); err != nil {\n    if strings.Contains(err.Error(), \"client stopped\") {\n        // shutdown race: requeue after restart\n        requeueAfterRestart(cfg)\n        return nil\n    }\n    return err\n}","preventionTips":["Avoid issuing consul config-entry writes during deployments/shutdowns","Requeue writes on restart via a reconciliation loop","Check server health endpoints before automation runs","Watch server logs for the deletion-goroutine stop message"],"tags":["nomad","consul","config-entry","shutdown"],"backgroundTag":"component-already-stopped","analyzedSha":"482b49bf1aec006f089bcfc7e632d8f6ac303e5e","analyzedAt":"2026-09-04T07:54:14.808Z","contentChangedAt":"2026-09-04T07:54:14.808Z","schemaVersion":2},"datasetVersion":"2026-09-08T15:18:49.778Z"}