hashicorp/terraform · error
failed to unmarshal JSON data into LockInfo struct: %w
Error message
failed to unmarshal JSON data into LockInfo struct: %w
What it means
Raised in getLockInfo when the lock file bytes were read successfully but json.Unmarshal into statemgr.LockInfo failed. The lock file object exists and is non-empty, but its content is not valid JSON or does not fit the LockInfo schema, so the lock holder identity (ID, Operation, Who, etc.) cannot be recovered.
Source
Thrown at internal/backend/remote-state/oci/client.go:320
NamespaceName: common.String(c.namespace),
ObjectName: common.String(c.lockFilePath),
BucketName: common.String(c.bucketName),
RequestMetadata: common.RequestMetadata{
RetryPolicy: getDefaultRetryPolicy(),
},
}
getResponse, err := c.objectStorageClient.GetObject(ctx, getRequest)
if err != nil {
return nil, "", fmt.Errorf("failed to get existing lock file: %w", err)
}
lockByteData, err := io.ReadAll(getResponse.Content)
if err != nil {
return nil, *getResponse.ETag, fmt.Errorf("failed to read existing lock file content: %w", err)
}
lockInfo := &statemgr.LockInfo{}
if err := json.Unmarshal(lockByteData, lockInfo); err != nil {
return lockInfo, "", fmt.Errorf("failed to unmarshal JSON data into LockInfo struct: %w", err)
}
return lockInfo, *getResponse.ETag, nil
}
func (c *RemoteClient) Unlock(id string) error {
ctx := context.TODO()
logger := logWithOperation("unlock-state-file").Named(c.lockFilePath)
logger.Info("unlocking remote state")
lockInfo, etag, err := c.getLockInfo(ctx)
if err != nil {
return fmt.Errorf("Failed to retrieve lock information from OCI Object Storage: %w", err)
}
// Verify that the provided lock ID matches the lock ID of the retrieved lock file.
if lockInfo.ID != id {
return &statemgr.LockError{
Info: lockInfo,
Err: fmt.Errorf("lock ID '%s' does not match the existing lock ID '%s'", id, lockInfo.ID),
}View on GitHub (pinned to c9def3e214)
Solutions
- Download the lock file (oci os object get) and inspect its bytes; if it is an error page or corrupt, delete it and re-acquire the lock.
- Confirm all teams/CI use a compatible Terraform version that shares the LockInfo schema.
- If the content is a valid-but-different JSON, map the fields manually or migrate to the current schema before deleting the lock.
- After cleaning up, run 'terraform force-unlock <id>' only if you are certain no real lock is held.
Defensive patterns
Strategy: validation
Validate before calling
// Validate the bytes are JSON before unmarshalling into LockInfo:
if !json.Valid(lockByteData) {
return lockInfo, "", fmt.Errorf("lock file is not valid JSON")
}
if err := json.Unmarshal(lockByteData, lockInfo); err != nil { ... } Type guard
var syntaxErr *json.SyntaxError
if errors.As(err, &syntaxErr) { /* malformed JSON */ }
var typeErr *json.UnmarshalTypeError
if errors.As(err, &typeErr) { /* schema mismatch */ } Try / catch
if err := json.Unmarshal(lockByteData, lockInfo); err != nil {
return lockInfo, "", fmt.Errorf("failed to unmarshal JSON data into LockInfo struct: %w", err)
} Prevention
- Standardize on a single Terraform version across teams to keep the LockInfo schema consistent.
- Never hand-edit or overwrite the lock object.
- If a proxy can cache an error page at the lock key, exclude object storage from caching.
When it happens
Trigger: json.Unmarshal(lockByteData, lockInfo) at client.go:319 fails: the lock file contains malformed JSON, is a different format (e.g. an HTML error page cached by a proxy), or has extra/missing fields incompatible with the LockInfo struct in this Terraform version.
Common situations: A lock file written by a different/newer Terraform whose LockInfo schema differs; manual corruption of the lock object; a transparent proxy returning an HTML error that got stored/cached at the lock key; partial write of the lock file.
Related errors
- object %q is empty
- uploadSinglePartObject: data is empty
- failed to read existing lock file content: %w
- Failed to retrieve lock information from OCI Object Storage:
- lock ID '%s' does not match the existing lock ID '%s'
AI-assisted analysis of hashicorp/terraform@c9def3e214 (2026-08-07).
Data as JSON: /api/errors/3dd15366d6581510.
Report an issue: GitHub.