Gorm: Error "no valid transaction" persists for subsequent calls on gorm.DB object

Created on 2 May 2019  路  7Comments  路  Source: go-gorm/gorm

What version of Go are you using (go version)?

go version go1.11.1 darwin/amd64

Which database and its version are you using?

PostgreSQL 11.2 (Debian 11.2-1.pgdg90+1) on x86_64-pc-linux-gnu, compiled by gcc (Debian 6.3.0-18+deb9u1) 6.3.0 20170516, 64-bit

Please provide a complete runnable program to reproduce your issue. IMPORTANT

package main

import (
    "fmt"
    "github.com/jinzhu/gorm"
)

type Foo struct {
    gorm.Model
    Bar string
}

func main() {
    // connect to database
    db, err := gorm.Open("postgres", "host=localhost port=5432 dbname=foo_db sslmode=disable user=dbadmin password=password")
    if err != nil {
        fmt.Printf("error connecting to database: %s", err)
    }

    // auto-migrating a struct
    err = db.AutoMigrate(&Foo{}).Error
    if err != nil {
        fmt.Printf("error while migration: %s", err)
    }

    if !db.HasTable(&Foo{}) {
        fmt.Print("Foo struct is not migrated successfully")
    }

    // trying to COMMIT/ROLLBACK a transaction block which was not initialized, obviously error will be thrown
    //err := db.Commit().Error //  no valid transaction
    err = db.Rollback().Error //  no valid transaction
    if err != nil {
        fmt.Printf("error while COMMITTING/ROLLING BACK the transaction: %s", err)
    }

        // each subsequent operation on the same connecction is failing
    foo := &Foo{Bar: "bar"}
    err = db.Create(foo).Error //  no valid transaction
    if err != nil {
        fmt.Print(err)
    }

    err = db.Find(foo).Error //  no valid transaction
    if err != nil {
        fmt.Print(err)
    }
}

So, basically, once we try to commit a database commit/rollback on a non-transactional block, then all the further requests are failing. My guess is that as the commit/rollback operation is called on the non-transactional block reference, it's setting one of the fields on the connection reference db such that it's getting stale.

The issue is already raised once before here, issue #2029.

gorm_v1

All 7 comments

On further investigation, it looks like the issue is because of the Error field on the database object. I explicitly set the error on the gorm.DB object, and tried to do a Find operation, and it starts failing. Once I reset the Error field to nil, it starts working.

package main

import (
    "errors"
    "fmt"
)

type Foo struct {
    Bar string
}

func main() {
    db := common.GetPostgresConnection()
    db.Error = errors.New("some random error")
    //db.Error = nil
    foo := &Foo{}
    err := db.Find(foo).Error
    if err != nil {
        panic(err)
    }
    fmt.Printf("%+v\n", foo)
}

After uncommenting the db.Error = nil line, it again works fine. Actually, I am using a singleton pattern, which creates the gorm.DB object once and uses it everywhere else, using sync.Once.

So, what I think I should do is always check for the Error field on the gorm.DB object, after fetching it. If it is not nil, I should set it to nil and then use it, or create a new gorm.DB object altogether.

Is it relate the issue/1620?

@mcauto Not exactly. That is more involved with a segmentation fault, that's not the case here. The subsequent calls to db object don't create panic, they just throw the error as mentioned above. Ideally, that error should be reset if it is not inside a transaction block.

Only in case of inside a transaction block, this error field should persist till the end of the transaction block, which I believe is working fine.

Still face this same issue @kaustubhmallik my problem also gets resolved by pointing db.Error =nil. but in my opinion, that is not a proper solution

@Umarhayat3 I know that solution is more like a hack, and IMHO it should be handled by the library itself. I am not sure how much of an effort will it take to fix it, but I will love to take it if possible. Any comments @mcauto?

@kaustubhmallik problem in my case I made a function returning a pointer to DB. And now I am using it throughout the application. Second thing I did is to avoid the db.begins() that also solved my problem and now I don't need this chunk of code anymore. thanks for your reply.

err := db.Find(foo).Error
    if err != nil {
        panic(err)
    }

This issue will be automatically closed because it is marked as GORM V1 issue, we have released the public testing GORM V2 release and its documents https://v2.gorm.io/docs/ already, the testing release has been used in some production services for a while, and going to release the final version in following weeks, we are still actively collecting feedback before it, please open a new issue for any suggestion or problem, thank you

Also check out https://github.com/go-gorm/gorm/wiki/GORM-V2-Release-Note-Draft for how to use the public testing version and its changelog

Was this page helpful?
0 / 5 - 0 ratings