{"record":{"id":"b7458fbb186b0cfe","repo":"hashicorp/terraform","slug":"error-getting-object-v","errorCode":null,"errorMessage":"error getting object: %#v","messagePattern":"error getting object: %#v","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/backend/remote-state/oss/client.go","lineNumber":428,"sourceCode":"\treturn fmt.Sprintf(\"%s/%s\", c.bucketName, c.stateFile)\n}\n\nfunc (c *RemoteClient) getObj() (*remote.Payload, error) {\n\tbucket, err := c.ossClient.Bucket(c.bucketName)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"error getting bucket %s: %#v\", c.bucketName, err)\n\t}\n\n\tif exist, err := bucket.IsObjectExist(c.stateFile); err != nil {\n\t\treturn nil, fmt.Errorf(\"estimating object %s is exist got an error: %#v\", c.stateFile, err)\n\t} else if !exist {\n\t\treturn nil, nil\n\t}\n\n\tvar options []oss.Option\n\toutput, err := bucket.GetObject(c.stateFile, options...)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"error getting object: %#v\", err)\n\t}\n\n\tbuf := bytes.NewBuffer(nil)\n\tif _, err := io.Copy(buf, output); err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to read remote state: %s\", err)\n\t}\n\tsum := md5.Sum(buf.Bytes())\n\tpayload := &remote.Payload{\n\t\tData: buf.Bytes(),\n\t\tMD5:  sum[:],\n\t}\n\n\t// If there was no data, then return nil\n\tif len(payload.Data) == 0 {\n\t\treturn nil, nil\n\t}\n\n\treturn payload, nil","sourceCodeStart":410,"sourceCodeEnd":446,"githubUrl":"https://github.com/hashicorp/terraform/blob/d32a084675427f5ac3f7d2868578ef8b2c1dc525/internal/backend/remote-state/oss/client.go#L410-L446","documentation":"Thrown by RemoteClient.getObj after IsObjectExist confirmed the object exists, when bucket.GetObject(stateFile, options...) returns an error. The existence check passed, so this failure is on the actual download (GetObject) - typically auth on read, SSE-C key mismatch, or object removed between the two calls. %#v prints the raw SDK error.","triggerScenarios":"bucket.GetObject(c.stateFile) fails after IsObjectExist returned true. Causes: object deleted between check and get (TOCTOU), missing GetObject permission despite Head permission, SSE-C encryption key not supplied or wrong, or a download stream error.","commonSituations":"Server-side encryption with customer keys configured but key env var unset; another process deleted the state object mid-run; permissions grant HeadObject but not GetObject; bucket policy changed between plan and apply.","solutions":["If using SSE-C, ensure the customer key configuration is present in the backend block on every run.","Re-run the operation - a TOCTOU delete by another writer is usually one-off.","Confirm the IAM/RAM principal has `GetObject` (not just `HeadObject`).","Check the SDK error wrapped in %#v for `AccessDenied` or `NoSuchKey` to narrow the cause."],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":"// if SSE-C is used, ensure the key is configured before reading\nif c.serverSideEncryption && c.customerEncryptionKey == nil {\n    return fmt.Errorf(\"state is SSE-C but no customer key provided\")\n}","typeGuard":null,"tryCatchPattern":"output, err := bucket.GetObject(c.stateFile, options...)\nif err != nil {\n    if isAccessDenied(err) { return fmt.Errorf(\"missing GetObject permission on %s: %w\", c.stateFile, err) }\n    if isNoSuchKey(err) { return nil, nil }\n    return nil, err\n}","preventionTips":["Keep HeadObject and GetObject permissions granted together.","Store the SSE-C customer key in a secrets manager referenced consistently.","Avoid concurrent writers that delete the state object."],"tags":["oss","alibaba","getobject","permissions","sse-c","toctou"],"backgroundTag":null,"analyzedSha":"d32a084675427f5ac3f7d2868578ef8b2c1dc525","analyzedAt":"2026-08-11T18:43:52.779Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}