{"record":{"id":"f062c6148a372bd7","repo":"hashicorp/nomad","slug":"error-executing-protected-function-w","errorCode":null,"errorMessage":"error executing protected function %w","messagePattern":"error executing protected function %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"api/locks.go","lineNumber":321,"sourceCode":"\n\t\t\tif !errors.Is(err, ErrLockConflict) {\n\t\t\t\terrChannel <- err\n\t\t\t}\n\t\t}\n\n\t\tif lockID != \"\" {\n\t\t\tll.locked = true\n\n\t\t\tfuncCtx, funcCancel := context.WithCancel(ctx)\n\t\t\tdefer funcCancel()\n\n\t\t\t// Execute the lock protected function.\n\t\t\tgo func() {\n\t\t\t\tdefer funcCancel()\n\t\t\t\tfor _, f := range protectedFuncs {\n\t\t\t\t\terr := f(funcCtx)\n\t\t\t\t\tif err != nil {\n\t\t\t\t\t\terrChannel <- fmt.Errorf(\"error executing protected function %w\", err)\n\t\t\t\t\t\treturn\n\t\t\t\t\t}\n\t\t\t\t\tcancel()\n\t\t\t\t}\n\t\t\t}()\n\n\t\t\t// Maintain lease is a blocking function, it will return if there is\n\t\t\t// an error maintaining the lease or the protected function returned.\n\t\t\terr = ll.maintainLease(funcCtx)\n\t\t\tif err != nil && !errors.Is(err, ErrLockConflict) {\n\t\t\t\terrChannel <- fmt.Errorf(\"error renewing the lease: %w\", err)\n\t\t\t}\n\t\t}\n\n\t\twaitTicker.Stop()\n\t\twaitTicker = time.NewTicker(ll.waitPeriod)\n\t\tselect {\n\t\tcase <-ctx.Done():","sourceCodeStart":303,"sourceCodeEnd":339,"githubUrl":"https://github.com/hashicorp/nomad/blob/482b49bf1aec006f089bcfc7e632d8f6ac303e5e/api/locks.go#L303-L339","documentation":"This error is sent through the leaser's error channel when one of the protected functions passed to LockLeaser.Start returns an error. The library aborts the remaining protected functions, cancels the function context, and Start surfaces the wrapped error. It is not a lock/HTTP error — it means your own callback failed while holding the lock.","triggerScenarios":"Any protectedFunc passed to LockLeaser.Start(ctx, f1, f2, ...) returning a non-nil error; f1 succeeds but a later fN fails, cancelling the funcCtx mid-run; the protected function returns an error because its own context was cancelled by an outer shutdown that it treats as fatal.","commonSituations":"Application logic inside the critical section hitting a database/connection error; a protected function returning ctx.Err() (context.Canceled) after the parent context is cancelled during shutdown; misconfigured dependencies used inside the protected function; the function attempting work that is no longer valid once the lease is lost.","solutions":["Fix the underlying error inside the protected function — inspect the wrapped cause with errors.Is/As on the error returned by Start (it is prefixed 'error executing protected function').","If the error is benign (e.g. context canceled during shutdown), swallow or filter it inside the protected function and return nil instead.","Log and return an error only for real failures; treat context.Canceled/DeadlineExceeded separately from operational errors.","If remaining protected functions must always run, do not return early on failure — collect and log per-function errors.","Retry the Start call with backoff if the failing protected work is transient (e.g. network to a backing service)."],"exampleFix":"// before\nfunc(ctx context.Context) error {\n    return db.Ping(ctx) // aborts all protected funcs on failure\n}\n// after\nfunc(ctx context.Context) error {\n    if err := db.Ping(ctx); err != nil {\n        if ctx.Err() != nil {\n            return nil // shutting down; don't abort the leaser\n        }\n        return err\n    }\n    return nil\n}","handlingStrategy":"try-catch","validationCode":"// validate dependencies the protected function needs BEFORE starting the leaser\nif err := db.Ping(context.Background()); err != nil {\n    return fmt.Errorf(\"precheck failed, not starting leaser: %w\", err)\n}","typeGuard":"func IsProtectedFuncError(err error) bool {\n    return err != nil && strings.Contains(err.Error(), \"error executing protected function\")\n}","tryCatchPattern":"err := leaser.Start(ctx, work)\nif err != nil {\n    if errors.Is(err, context.Canceled) || errors.Is(err, context.DeadlineExceeded) {\n        // shutdown, not a real failure\n        return nil\n    }\n    return fmt.Errorf(\"protected work failed: %w\", err)\n}","preventionTips":["Make protected functions return nil for benign cancellations (ctx.Err during shutdown)","Fix or retry failures inside the protected function instead of propagating them when non-fatal","Keep protected functions idempotent so the whole Start can be retried after failure","Log the wrapped cause (everything after 'error executing protected function') to find the real failure","Pre-validate external dependencies (DB, queue) before entering the lock-protected section"],"tags":["go","callback","context","error-wrapping"],"backgroundTag":"protected-function-failed","analyzedSha":"482b49bf1aec006f089bcfc7e632d8f6ac303e5e","analyzedAt":"2026-09-04T07:54:14.808Z","contentChangedAt":"2026-09-04T07:54:14.808Z","schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}