hashicorp/terraform · error
object %q is empty
Error message
object %q is empty
What it means
Raised in getObject when GetObject and the body read both succeeded but the resulting payload has zero bytes (len(payload.Data) == 0). The comment at client.go:121 explicitly notes this replaces a prior 'nil, nil' that silently returned an empty state, so an empty-but-existing object is now treated as a corruption error rather than a fresh init.
Source
Thrown at internal/backend/remote-state/oci/client.go:123
contentArray, err := io.ReadAll(getResponse.Content)
if err != nil {
return nil, fmt.Errorf("unable to read 'content' from response: %w", err)
}
// Compute MD5 hash
md5Hash := getResponse.ContentMd5
if md5Hash == nil || len(*md5Hash) == 0 {
md5Hash = getResponse.OpcMultipartMd5
}
// Construct payload
payload := &remote.Payload{
Data: contentArray,
MD5: []byte(*md5Hash),
}
// Return an error instead of `nil, nil` if the object is empty
if len(payload.Data) == 0 {
return nil, fmt.Errorf("object %q is empty", c.path)
}
return payload, nil
}
func (c *RemoteClient) Put(data []byte) tfdiags.Diagnostics {
var diags tfdiags.Diagnostics
logger := logWithOperation("upload-state-file").Named(c.path)
ctx := context.WithValue(context.Background(), "logger", logger)
dataSize := int64(len(data))
sum := md5.Sum(data)
var err error
if dataSize > DefaultFilePartSize {
logger.Info("Using Multipart Feature")
var multipartUploadData = MultipartUploadData{
client: c,
Data: data,View on GitHub (pinned to c9def3e214)
Solutions
- List object versions: 'oci os object list-versions --bucket-name <b> --namespace <ns> --prefix <key>'; if versioning is on, restore the last non-empty version.
- If you have a known-good backup, re-upload it (oci os object put) to the same key, or delete the 0-byte object and run 'terraform init' to let Terraform treat the state as absent.
- Audit who/what wrote the 0-byte object via the OCI audit log around the object's last-modified time.
- If the empty object is unexpected on a fresh backend, confirm no other pipeline shares the same key and overwrote it with empty content.
Defensive patterns
Strategy: validation
Validate before calling
// After a successful Get, validate payload before trusting it as state:
payload, err := c.getObject(ctx)
if err == nil && len(payload.Data) == 0 {
return nil, fmt.Errorf("object %q is empty", c.path) // (this is what the lib now does)
} Try / catch
if len(payload.Data) == 0 {
return nil, fmt.Errorf("object %q is empty", c.path)
} Prevention
- Never let a 0-byte object land on the state key (it later trips this read error).
- Enable object versioning so a corrupted/empty object can be rolled back.
- Audit writes to the state key via OCI audit logs.
When it happens
Trigger: The state object at c.path exists (HeadObject did not 404) and GetObject returned HTTP 200, but the object body is empty. Reachable when something wrote a 0-byte object to the state key: a botched upload, an aborted multipart upload that left a 0-byte object, or an external process truncating the object.
Common situations: A previous 'terraform apply' crashed during upload leaving a 0-byte tfstate; someone manually emptied the object; a migration/import tool created the key without content; an aborted multipart commit leaving a placeholder object.
Related errors
- uploadSinglePartObject: data is empty
- failed to unmarshal JSON data into LockInfo struct: %w
- failed to access object '%s' in bucket '%s': %w
- failed to access object HttpStatusCode: %d OpcRequestId: %s
- unable to read 'content' from response: %w
AI-assisted analysis of hashicorp/terraform@c9def3e214 (2026-08-07).
Data as JSON: /api/errors/4ba763422d441f44.
Report an issue: GitHub.