{"record":{"id":"3dd15366d6581510","repo":"hashicorp/terraform","slug":"failed-to-unmarshal-json-data-into-lockinfo-struct","errorCode":null,"errorMessage":"failed to unmarshal JSON data into LockInfo struct: %w","messagePattern":"failed to unmarshal JSON data into LockInfo struct: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/backend/remote-state/oci/client.go","lineNumber":320,"sourceCode":"\t\tNamespaceName: common.String(c.namespace),\n\t\tObjectName:    common.String(c.lockFilePath),\n\t\tBucketName:    common.String(c.bucketName),\n\t\tRequestMetadata: common.RequestMetadata{\n\t\t\tRetryPolicy: getDefaultRetryPolicy(),\n\t\t},\n\t}\n\n\tgetResponse, err := c.objectStorageClient.GetObject(ctx, getRequest)\n\tif err != nil {\n\t\treturn nil, \"\", fmt.Errorf(\"failed to get existing lock file: %w\", err)\n\t}\n\tlockByteData, err := io.ReadAll(getResponse.Content)\n\tif err != nil {\n\t\treturn nil, *getResponse.ETag, fmt.Errorf(\"failed to read existing lock file content: %w\", err)\n\t}\n\tlockInfo := &statemgr.LockInfo{}\n\tif err := json.Unmarshal(lockByteData, lockInfo); err != nil {\n\t\treturn lockInfo, \"\", fmt.Errorf(\"failed to unmarshal JSON data into LockInfo struct: %w\", err)\n\t}\n\treturn lockInfo, *getResponse.ETag, nil\n}\nfunc (c *RemoteClient) Unlock(id string) error {\n\tctx := context.TODO()\n\tlogger := logWithOperation(\"unlock-state-file\").Named(c.lockFilePath)\n\tlogger.Info(\"unlocking remote state\")\n\tlockInfo, etag, err := c.getLockInfo(ctx)\n\n\tif err != nil {\n\t\treturn fmt.Errorf(\"Failed to retrieve lock information from OCI Object Storage: %w\", err)\n\t}\n\t// Verify that the provided lock ID matches the lock ID of the retrieved lock file.\n\tif lockInfo.ID != id {\n\t\treturn &statemgr.LockError{\n\t\t\tInfo: lockInfo,\n\t\t\tErr:  fmt.Errorf(\"lock ID '%s' does not match the existing lock ID '%s'\", id, lockInfo.ID),\n\t\t}","sourceCodeStart":302,"sourceCodeEnd":338,"githubUrl":"https://github.com/hashicorp/terraform/blob/c9def3e214014c1188faabfc4a5bde5095139765/internal/backend/remote-state/oci/client.go#L302-L338","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":null,"handlingStrategy":"validation","validationCode":"// Validate the bytes are JSON before unmarshalling into LockInfo:\nif !json.Valid(lockByteData) {\n    return lockInfo, \"\", fmt.Errorf(\"lock file is not valid JSON\")\n}\nif err := json.Unmarshal(lockByteData, lockInfo); err != nil { ... }","typeGuard":"var syntaxErr *json.SyntaxError\nif errors.As(err, &syntaxErr) { /* malformed JSON */ }\nvar typeErr *json.UnmarshalTypeError\nif errors.As(err, &typeErr) { /* schema mismatch */ }","tryCatchPattern":"if err := json.Unmarshal(lockByteData, lockInfo); err != nil {\n    return lockInfo, \"\", fmt.Errorf(\"failed to unmarshal JSON data into LockInfo struct: %w\", err)\n}","preventionTips":["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."],"tags":["oci","object-storage","json","locking","unmarshal","data-integrity","terraform-state"],"analyzedSha":"c9def3e214014c1188faabfc4a5bde5095139765","analyzedAt":"2026-08-07T15:39:49.278Z","schemaVersion":2},"datasetVersion":"2026-08-07T20:17:04.800Z"}