{"record":{"id":"a42b08cc52b56bd4","repo":"hashicorp/terraform","slug":"uploadsinglepartobject-data-is-empty","errorCode":null,"errorMessage":"uploadSinglePartObject: data is empty","messagePattern":"uploadSinglePartObject: data is empty","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/backend/remote-state/oci/client.go","lineNumber":165,"sourceCode":"\t\tif err != nil && dataSize <= MaxFilePartSize {\n\t\t\tlogger.Error(fmt.Sprintf(\"Multipart upload failed, falling back to single part upload: %v\", err))\n\t\t\terr = c.uploadSinglePartObject(ctx, data, sum[:])\n\t\t}\n\t} else {\n\t\terr = c.uploadSinglePartObject(ctx, data, sum[:])\n\t}\n\tif err != nil {\n\t\treturn diags.Append(err)\n\t}\n\n\treturn diags\n}\n\nfunc (c *RemoteClient) uploadSinglePartObject(ctx context.Context, data, sum []byte) error {\n\tlogger := ctx.Value(\"logger\").(hclog.Logger).Named(\"singlePartUpload\")\n\tlogger.Info(\"Uploading single part object\")\n\tif len(data) == 0 {\n\t\treturn fmt.Errorf(\"uploadSinglePartObject: data is empty\")\n\t}\n\n\tcontentType := \"application/json\"\n\n\tputRequest := objectstorage.PutObjectRequest{\n\t\tContentType:   common.String(contentType),\n\t\tNamespaceName: common.String(c.namespace),\n\t\tObjectName:    common.String(c.path),\n\t\tBucketName:    common.String(c.bucketName),\n\t\tPutObjectBody: io.NopCloser(bytes.NewReader(data)),\n\t\tContentMD5:    common.String(base64.StdEncoding.EncodeToString(sum)),\n\t\tRequestMetadata: common.RequestMetadata{\n\t\t\tRetryPolicy: getDefaultRetryPolicy(),\n\t\t},\n\t}\n\n\t// Handle encryption settings\n\tif c.kmsKeyID != \"\" {","sourceCodeStart":147,"sourceCodeEnd":183,"githubUrl":"https://github.com/hashicorp/terraform/blob/d32a084675427f5ac3f7d2868578ef8b2c1dc525/internal/backend/remote-state/oci/client.go#L147-L183","documentation":"Defensive guard in uploadSinglePartObject: it rejects any call where the data slice is empty. State writes should always carry serialized state; an empty slice indicates a caller bug upstream rather than a legitimate write.","triggerScenarios":"Caller passed a nil/zero-length byte slice to uploadSinglePartObject; the state serializer returned no bytes; a code path that should have used the empty-state init flow in StateMgr instead tried to Put nothing.","commonSituations":"Bug in a fork that produces empty serialized state; test fixtures calling Put([]byte{}); a refactor that bypassed the `state == nil -> states.NewState()` init in backend_state.go:94.","solutions":["Ensure the state serializer always produces non-empty bytes before calling Put.","For initial empty state, rely on StateMgr's init flow (it writes states.NewState(), which is non-empty JSON) rather than calling Put([]byte{}).","If hit in custom code, debug why len(data)==0 upstream — this guard means the precondition is wrong."],"exampleFix":"// before: caller uploads empty bytes\nclient.Put([]byte{})  // -> \"uploadSinglePartObject: data is empty\"\n// after: write a proper (possibly empty) state object\nempty := states.NewState()\nvar buf bytes.Buffer\njson.NewEncoder(&buf).Encode(empty)\nclient.Put(buf.Bytes())","handlingStrategy":"validation","validationCode":"// Reject empty payloads upstream, before reaching uploadSinglePartObject\nfunc putState(c *RemoteClient, data []byte) tfdiags.Diagnostics {\n    if len(data) == 0 { return tfdiags.Diagnostics{}.Append(fmt.Errorf(\"refusing to upload empty state\")) }\n    return c.Put(data)\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Always serialize through states.NewState() (non-empty JSON) for initial state.","Unit-test the state serializer to ensure it never returns zero bytes.","Treat an empty payload as a caller bug, not a normal condition.","Do not bypass StateMgr's init flow when seeding a new workspace."],"tags":["oci","object-storage","validation","precondition"],"backgroundTag":null,"analyzedSha":"d32a084675427f5ac3f7d2868578ef8b2c1dc525","analyzedAt":"2026-08-11T18:43:52.779Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}