{"record":{"id":"d4d3ee4797784ad3","repo":"hashicorp/nomad","slug":"multiple-lock-operations","errorCode":null,"errorMessage":"multiple lock operations","messagePattern":"multiple lock operations","errorType":"validation","errorClass":null,"httpStatus":400,"severity":"error","filePath":"command/agent/variable_endpoint.go","lineNumber":298,"sourceCode":"}\n\nfunc isOneAndOnlyOneSet(a, b, c bool) bool {\n\treturn (a || b || c) && !a != !b != !c != !(a && b && c)\n}\n\n// getLockOperation returns the lock operation to be performed in case there is\n// one. It returns error if more than one is set.\nfunc getLockOperation(queryParams url.Values) (string, error) {\n\t_, renewLock := queryParams[renewLockQueryParam]\n\t_, acquireLock := queryParams[acquireLockQueryParam]\n\t_, releaseLock := queryParams[releaseLockQueryParam]\n\n\tif !renewLock && !acquireLock && !releaseLock {\n\t\treturn \"\", nil\n\t}\n\n\tif !isOneAndOnlyOneSet(renewLock, acquireLock, releaseLock) {\n\t\treturn \"\", errors.New(\"multiple lock operations\")\n\t}\n\n\tswitch {\n\tcase renewLock:\n\t\treturn renewLockQueryParam, nil\n\tcase acquireLock:\n\t\treturn acquireLockQueryParam, nil\n\tcase releaseLock:\n\t\treturn releaseLockQueryParam, nil\n\tdefault:\n\t\treturn \"\", errors.New(\"unspecified lock operation\")\n\t}\n}\n","sourceCodeStart":280,"sourceCodeEnd":312,"githubUrl":"https://github.com/hashicorp/nomad/blob/482b49bf1aec006f089bcfc7e632d8f6ac303e5e/command/agent/variable_endpoint.go#L280-L312","documentation":"getLockOperation in command/agent/variable_endpoint.go determines which single lock operation (renew, acquire, release) a variable request carries. If more than one of the renewLock/acquireLock/releaseLock flags is set, the request is ambiguous and the function returns this error. A variable lock request must express exactly zero or one lock operation.","triggerScenarios":"Issuing a variable write/update via VariableSpecificRequest with two or more lock query flags simultaneously — e.g. a request setting both `lock=true` (acquire) and `unlock=true` (release), or renew plus release in the same body/query.","commonSituations":"Hand-built API calls combining lock query parameters; templating bugs where a client sets all lock fields to the same boolean; retry logic re-sending a request that merges two operations; misuse of the variables HTTP API with both lock and unlock params.","solutions":["Send only one lock operation per request: set exactly one of acquire, release, or renew and leave the others unset.","Split combined operations into sequential requests (acquire first, then later renew/release).","Audit client code/automation for defaults that set multiple lock booleans (e.g. `lock: true, unlock: true`).","Check for zero values being explicitly serialized: omit unset lock fields instead of sending explicit false/true pairs."],"exampleFix":"// before: ambiguous request\nPOST /v1/var/path?lock=true&unlock=true\n// after: single operation per call\nPOST /v1/var/path?lock=true\nPOST /v1/var/path?unlock=true","handlingStrategy":"validation","validationCode":"ops := []bool{renew, acquire, release}\ncount := 0\nfor _, o := range ops {\n    if o {\n        count++\n    }\n}\nif count > 1 {\n    return errors.New(\"send only one lock operation per variable request\")\n}","typeGuard":null,"tryCatchPattern":"if err := updateVariable(req); err != nil {\n    if strings.Contains(err.Error(), \"multiple lock operations\") {\n        return fmt.Errorf(\"split request: set only one of lock/unlock/renew per call\")\n    }\n    return err\n}","preventionTips":["Model lock operations as an enum so only one can ever be set.","Omit unset lock fields in serialized requests instead of sending explicit flags.","Review automation scripts that build lock query parameters."],"tags":["variables","lock","validation","http-api"],"backgroundTag":"conflicting-request-parameters","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"}