Hi, little issue here when writing custom unmarshalling interfaces.

I have a simple interface that binds UUID types. I noticed that when an error occurs during parsing, the error message in the response just includes the raw error text and no mention of the field name. As a user, receiving an error text without the actual field name can be very confusing.

There's no access to the field name in the UnmarshalParam implementation, and it seems quite nontrivial to otherwise insert the field name that is erroring. We could use a level of convenience on top of this, either automatically including the field name in the error response, or letting us have easier access to it during unmarshalling.

Comment From: mukunda-

Minimal failing testcase:

type BindUuid struct {
    uuid.UUID
}

func (b *BindUuid) UnmarshalParam(param string) error {
    parsed, err := uuid.Parse(param)
    if err != nil {
        return err
    }

    *b = BindUuid(BindUuid{parsed})
    return nil
}

func TestGinUuids(t *testing.T) {
    type Request struct {
        Uuid1 BindUuid `form:"uuid1" binding:"required"`
        Uuid2 BindUuid `form:"uuid2" binding:"required"`
        Uuid3 BindUuid `form:"uuid3" binding:"required"`
        Uuid4 BindUuid `form:"uuid4" binding:"required"`
    }

    R := gin.New()
    R.GET("/test", func(c *gin.Context) {
        req := Request{}
        if err := c.ShouldBindQuery(&req); err != nil {
            c.String(400, err.Error())
            return
        }

        c.String(200, "ok")
    })

    {
        w := httptest.NewRecorder()
        req := httptest.NewRequest("GET", "/test?uuid1=7db82ade-597a-46e9-bd7a-4bc66b3a2461&uuid2=7db82ade-597a-46e9-bd7a-4bc66b3a2462&uuid3=7db82ade-597a-46e9-bd7a-4bc66b3a2463&uuid4=7db82ade-597a-46e9-bd7a-4bc66b3l2464", nil)
        R.ServeHTTP(w, req)
        if w.Code != 400 {
            t.Fatalf("expected 400, got %d", w.Code)
        }
        if !strings.Contains(w.Body.String(), "uuid4") {
            t.Fatalf("expected uuid4 in the response error: %s", w.Body.String())
        }
    }
}

Not revealing the field name in the response can make for a difficult user experience.

Comment From: mukunda-

My workaround for this is to: 1. Don't return errors from the validation function. Instead, store the error in the returned struct. 2. Add a custom validator "binduuid" which checks the error and fails validation. 3. In the validation translator, format the message with the field name and the error.

Very much not ideal to have this excess of setup code just because I want to see the field name in a parsing error message.