{"record":{"id":"95622f624254ebbe","repo":"AdguardTeam/AdGuardHome","slug":"login-expected-length-d-got-d","errorCode":null,"errorMessage":"login: expected length %d, got %d","messagePattern":"login: expected length (.+?), got (.+?)","errorType":"error_code","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/aghuser/sessionstorage.go","lineNumber":294,"sourceCode":"\n\t// bboltSessionNameLen is the length of the name field in the binary entry\n\t// stored in bbolt.\n\tbboltSessionNameLen = 2\n)\n\n// bboltDecode deserializes decodes a binary data into a session.\nfunc bboltDecode(data []byte) (s *Session, err error) {\n\tif len(data) < bboltSessionExpireLen+bboltSessionNameLen {\n\t\treturn nil, fmt.Errorf(\"length of the data is less than expected: got %d\", len(data))\n\t}\n\n\texpireData := data[:bboltSessionExpireLen]\n\tnameLenData := data[bboltSessionExpireLen : bboltSessionExpireLen+bboltSessionNameLen]\n\tnameData := data[bboltSessionExpireLen+bboltSessionNameLen:]\n\n\tnameLen := binary.BigEndian.Uint16(nameLenData)\n\tif len(nameData) != int(nameLen) {\n\t\treturn nil, fmt.Errorf(\"login: expected length %d, got %d\", nameLen, len(nameData))\n\t}\n\n\texpire := binary.BigEndian.Uint32(expireData)\n\n\treturn &Session{\n\t\tExpire:    time.Unix(int64(expire), 0),\n\t\tUserLogin: Login(nameData),\n\t}, nil\n}\n\n// bboltEncode serializes a session properties into a binary data.\nfunc bboltEncode(s *Session) (data []byte) {\n\tdata = make([]byte, bboltSessionExpireLen+bboltSessionNameLen+len(s.UserLogin))\n\n\texpireData := data[:bboltSessionExpireLen]\n\tnameLenData := data[bboltSessionExpireLen : bboltSessionExpireLen+bboltSessionNameLen]\n\tnameData := data[bboltSessionExpireLen+bboltSessionNameLen:]\n","sourceCodeStart":276,"sourceCodeEnd":312,"githubUrl":"https://github.com/AdguardTeam/AdGuardHome/blob/b41aefbe51c8dde65e2c50f093996afa0502edf9/internal/aghuser/sessionstorage.go#L276-L312","documentation":"bboltDecode validates that the trailing name bytes match the 2-byte big-endian length prefix; a mismatch means the record is internally inconsistent and cannot be safely decoded. Like error 61, it points to corrupted or foreign data in the sessions bucket.","triggerScenarios":"A bucket value where the declared login-name length does not equal the remaining bytes — truncated record, tampering, or an incompatible serialization version.","commonSituations":"Crash during a session write; manual editing of the db; format drift between versions.","solutions":["Delete the sessions db file so invalid records are purged and users re-login","Pin one AdGuard Home version (avoid downgrade after upgrade)","Run bbolt integrity checks / restore backup"],"exampleFix":null,"handlingStrategy":"fallback","validationCode":null,"typeGuard":"func sessionNameLenMatches(b []byte) bool {\n\tif len(b) < 6 { return false }\n\treturn int(binary.BigEndian.Uint16(b[4:6])) == len(b)-6\n}","tryCatchPattern":"// treat as corrupt record: purge db, restart clean\nif err != nil && strings.Contains(err.Error(), \"login: expected length\") { purgeSessionDB() }","preventionTips":["Pin versions consistently","Use fsync-friendly local storage for the db"],"tags":["bbolt","serialization","validation","sessions"],"backgroundTag":"data-deserialization-failed","analyzedSha":"b41aefbe51c8dde65e2c50f093996afa0502edf9","analyzedAt":"2026-08-27T04:57:55.097Z","schemaVersion":2},"datasetVersion":"2026-08-27T08:17:20.692Z"}