juicedata/juicefs · error
invalid type: %T
Error message
invalid type: %T
What it means
Thrown by dbMeta.getSession when the row passed to it is neither *session2 (current schema) nor *session (legacy schema). This is an internal invariant: GetSession/FindSession only ever construct those two row types, so this branch should be unreachable. It surfaces only if internal code evolves inconsistently (a new row type added without extending the switch).
Source
Thrown at pkg/meta/sql.go:836
}
func (m *dbMeta) getSession(row interface{}, detail bool) (*Session, error) {
var s Session
var info []byte
switch row := row.(type) {
case *session2:
s.Sid = row.Sid
s.Expire = time.Unix(row.Expire, 0)
info = row.Info
case *session:
s.Sid = row.Sid
s.Expire = time.Unix(row.Heartbeat, 0).Add(time.Minute * 5)
info = row.Info
if info == nil { // legacy client has no info
info = []byte("{}")
}
default:
return nil, fmt.Errorf("invalid type: %T", row)
}
if err := json.Unmarshal(info, &s); err != nil {
return nil, fmt.Errorf("corrupted session info; json error: %s", err)
}
if detail {
var (
srows []sustained
frows []flock
prows []plock
)
err := m.roTxn(Background(), func(ses *xorm.Session) error {
if err := ses.Find(&srows, &sustained{Sid: s.Sid}); err != nil {
return fmt.Errorf("find sustained %d: %s", s.Sid, err)
}
s.Sustained = make([]Ino, 0, len(srows))
for _, srow := range srows {
s.Sustained = append(s.Sustained, srow.Inode)
}View on GitHub (pinned to c9a67b23e8)
Solutions
- Inspect the %T in the message to find which row type leaked into getSession.
- Add a case for that row type in the switch in getSession, mapping Sid/Expire/Info.
- If seen in stock JuiceFS, file a bug — it indicates an internal code path inconsistency.
Example fix
// before (internal code passes an unmapped row type)
return nil, fmt.Errorf("invalid type: %T", row)
// after: extend the switch
switch row := row.(type) {
case *session2: ...
case *session: ...
case *myNewSessionRow:
s.Sid = row.Sid
s.Expire = time.Unix(row.Expire, 0)
info = row.Info
} Defensive patterns
Strategy: type-guard
Validate before calling
// assert the row type before calling internal getSession
switch row.(type) {
case *meta.Session2, *meta.LegacySession:
// ok
default:
log.Fatalf("unsupported session row type %T", row)
} Type guard
func validSessionRow(row interface{}) bool {
switch row.(type) {
case *session2, *session:
return true
}
return false
} Try / catch
if err != nil {
if strings.Contains(err.Error(), "invalid type: ") {
logger.Fatalf("internal bug: unmapped session row type — report to maintainers")
}
} Prevention
- When adding a new session table variant, update every switch over session row types in one change.
- Cover getSession with unit tests for all row types.
When it happens
Trigger: A developer calls getSession with a row type other than *session2 or *session — practically only possible when modifying pkg/meta/sql.go and adding a new session table/row type without updating the switch. Not triggerable by normal API users.
Common situations: During development of a new metadata schema variant; during a custom fork or patch of the SQL engine; never in production for stock JuiceFS.
Understand the failure class
Background: Type mismatch errors: IllegalArgumentException, TypeError and type guards across 150 open-source libraries — this error's family across 150 libraries.
Related errors
- insert new session %d: %s
- new session: %s
- get session ID: %s
- create session: %s
- corrupted session info; json error: %s
AI-assisted analysis of juicedata/juicefs@c9a67b23e8 (2026-09-06).
Data as JSON: /api/errors/7a36bfa2a619e731.
Report an issue: GitHub.