{"record":{"id":"135f9f6485a2d9bf","repo":"hashicorp/terraform","slug":"http-remote-state-endpoint-invalid-auth","errorCode":null,"errorMessage":"HTTP remote state endpoint invalid auth","messagePattern":"HTTP remote state endpoint invalid auth","errorType":"http","errorClass":null,"httpStatus":403,"severity":"error","filePath":"internal/backend/remote-state/http/client.go","lineNumber":101,"sourceCode":"\t}\n\tc.lockID = \"\"\n\n\tjsonLockInfo := info.Marshal()\n\tresp, err := c.httpRequest(c.LockMethod, c.LockURL, &jsonLockInfo, \"lock\")\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\tdefer resp.Body.Close()\n\n\tswitch resp.StatusCode {\n\tcase http.StatusOK:\n\t\tc.lockID = info.ID\n\t\tc.jsonLockInfo = jsonLockInfo\n\t\treturn info.ID, nil\n\tcase http.StatusUnauthorized:\n\t\treturn \"\", fmt.Errorf(\"HTTP remote state endpoint requires auth\")\n\tcase http.StatusForbidden:\n\t\treturn \"\", fmt.Errorf(\"HTTP remote state endpoint invalid auth\")\n\tcase http.StatusConflict, http.StatusLocked:\n\t\tdefer resp.Body.Close()\n\t\tbody, err := io.ReadAll(resp.Body)\n\t\tif err != nil {\n\t\t\treturn \"\", &statemgr.LockError{\n\t\t\t\tErr: fmt.Errorf(\"HTTP remote state already locked, failed to read body\"),\n\t\t\t}\n\t\t}\n\t\texisting := statemgr.LockInfo{}\n\t\terr = json.Unmarshal(body, &existing)\n\t\tif err != nil {\n\t\t\treturn \"\", &statemgr.LockError{\n\t\t\t\tErr: fmt.Errorf(\"HTTP remote state already locked, failed to unmarshal body\"),\n\t\t\t}\n\t\t}\n\t\treturn \"\", &statemgr.LockError{\n\t\t\tInfo: &existing,\n\t\t\tErr:  fmt.Errorf(\"HTTP remote state already locked: ID=%s\", existing.ID),","sourceCodeStart":83,"sourceCodeEnd":119,"githubUrl":"https://github.com/hashicorp/terraform/blob/d32a084675427f5ac3f7d2868578ef8b2c1dc525/internal/backend/remote-state/http/client.go#L83-L119","documentation":"The lock request returned HTTP 403 Forbidden. Credentials were accepted as authentication but the authenticated principal is not permitted to perform the lock operation on this endpoint. Distinct from 401 (no/bad auth) — here the server knows who you are but denies the action.","triggerScenarios":"Valid credentials but the user/service account lacks write/lock permission on the state endpoint; RBAC or ACL policy denies the LOCK method or the resource.","commonSituations":"Read-only service account used for a backend that writes; server-side permission changed; correct user but wrong role; endpoint requires a specific group/claim the principal lacks.","solutions":["Grant the principal lock/write permission on the state endpoint (server-side RBAC/ACL).","Switch to a service account with the required role.","Confirm with curl -u user:pass -X <lock_method> -i <lock_address> that a 2xx is returned once permissions are fixed."],"exampleFix":"// Role/policy change required server-side; e.g. grant LOCK on /terraform/*\n// then verify:\n//   curl -u \"$U:$P\" -X LOCK -i https://state.example.com/lock","handlingStrategy":"validation","validationCode":"# Pre-flight: confirm the principal can perform a lock-shaped request\ncurl -sS -u \"$TF_HTTP_USERNAME:$TF_HTTP_PASSWORD\" -X \"${TF_HTTP_LOCK_METHOD:-LOCK}\" \\\n  -o /dev/null -w 'http=%{http_code}\\n' \"${TF_HTTP_LOCK_ADDRESS:-$TF_HTTP_ADDRESS}\" \\\n  | grep -qE 'http=(200|201|204|409|423)' || echo 'WARN: principal may lack lock permission'","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Grant the service account explicit write/lock permission on the state endpoint.","Use a dedicated principal per workspace so RBAC is auditable.","Probe with curl -X <lock_method> before running terraform apply."],"tags":["auth","authorization","http","lock","http-backend"],"backgroundTag":null,"analyzedSha":"d32a084675427f5ac3f7d2868578ef8b2c1dc525","analyzedAt":"2026-08-11T18:43:52.779Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}