AlistGo/alist · error
cannot scan %T
Error message
cannot scan %T
What it means
Same Scanner-hook pattern as Paths.Scan but for the Roles type ([]int stored as JSON). (*Roles).Scan only accepts []byte, string, or nil; any other driver value type triggers 'cannot scan %T'. It is the deserialization boundary between the DB column and the []int role list.
Source
Thrown at internal/model/roles.go:25
)
type Roles []int
func (r Roles) Value() (driver.Value, error) {
return json.Marshal([]int(r))
}
func (r *Roles) Scan(value interface{}) error {
switch v := value.(type) {
case []byte:
return json.Unmarshal(v, (*[]int)(r))
case string:
return json.Unmarshal([]byte(v), (*[]int)(r))
case nil:
*r = nil
return nil
default:
return fmt.Errorf("cannot scan %T", value)
}
}
func (r Roles) Contains(role int) bool {
for _, v := range r {
if v == role {
return true
}
}
return false
}
View on GitHub (pinned to 843d9dc814)
Solutions
- Look at the '%T' in the message to see the concrete type your driver returns.
- Keep the roles column as a text/JSON string type so Scan receives []byte or string.
- Extend the type switch with the driver-specific type if needed.
- Fix rows whose roles column is not a valid JSON array of integers.
Example fix
// before
case string:
return json.Unmarshal([]byte(v), (*[]int)(r))
// after
case string:
return json.Unmarshal([]byte(v), (*[]int)(r))
case json.RawMessage:
return json.Unmarshal(v, (*[]int)(r)) Defensive patterns
Strategy: type-guard
Type guard
tv := reflect.TypeOf(value)
if value != nil && tv != nil && tv.Kind() != reflect.String && tv.Kind() != reflect.Slice {
return fmt.Errorf("roles column must arrive as string or []byte, got %T", value)
} Try / catch
if err := user.Roles.Scan(col); err != nil {
if strings.HasPrefix(err.Error(), "cannot scan") {
// inspect %T, fix column type or extend the switch
}
} Prevention
- Store roles strictly as a JSON array of integers in a text column.
- Cover Roles round-trip in DB integration tests per backend.
- Extend the Scan switch when adopting a driver that returns typed JSON values.
When it happens
Trigger: Loading a user row where the roles column is returned by the driver as a typed JSON value, a number, or another non-text type; the column contains data but the driver does not present it as bytes/string.
Common situations: Database backend change altering how JSON columns are scanned; Postgres JSONB via a driver that returns a non-[]byte representation; schema drifted after migrations; corrupted column content.
Related errors
- cannot scan %T
- [doubao_new] decode response failed (status: %s, content-typ
- failed to parse response: %v
- check share id availability: %w
- missing cookie or qrcode account
AI-assisted analysis of AlistGo/alist@843d9dc814 (2026-08-15).
Data as JSON: /api/errors/29ba3461c99009f7.
Report an issue: GitHub.