go-sql-driver/mysql · error
reader ' ' is not registered
Error message
reader '%s' is not registered
What it means
LOAD DATA LOCAL INFILE referenced a 'Reader::<name>' that was never registered with mysql.RegisterReaderHandler. For security and predictability the driver only serves readers it knows about.
Solutions
- Register the handler with mysql.RegisterReaderHandler using the exact name that appears in the SQL.
- Check for typos, case, and the 'Reader::' prefix between the SQL string and the registration call.
- Call RegisterReaderHandler before the db.Exec that triggers LOAD DATA.
Example fix
// before
db.Exec("LOAD DATA LOCAL INFILE 'Reader::data' INTO TABLE t")
// (no registration)
// after
mysql.RegisterReaderHandler("data", func() io.Reader { return strings.NewReader("a,b\n") })
db.Exec("LOAD DATA LOCAL INFILE 'Reader::data' INTO TABLE t") Defensive patterns
Strategy: validation
Validate before calling
// Verify the reader name is registered before issuing LOAD DATA.
// (Registry is package-private; track registration in your own map.)
if _, ok := myReaderRegistry[name]; !ok {
return fmt.Errorf("reader %q not registered", name)
} Type guard
null
Try / catch
// The error is returned from db.Exec.
if _, err := db.Exec(q); err != nil {
if strings.Contains(err.Error(), "is not registered") {
// register the reader and retry
}
} Prevention
- Centralize reader registration and reference the same name constant in SQL.
- Register readers at startup (init/main) before any LOAD DATA.
- Unit-test the exact 'Reader::name' string against the registration.
When it happens
Trigger: Executing "LOAD DATA LOCAL INFILE 'Reader::data'" without having called mysql.RegisterReaderHandler("data", ...), or with a name that does not match (typo, case, prefix).
Common situations: Forgetting to register the handler; registering under a different name; registration living in a different init()/process.
Related errors
- local file ' ' is not registered
- reader ' ' is
- argument count mismatch
- can't convert %T to time.Time
- cannot convert type: %T
AI-assisted analysis of go-sql-driver/mysql@03d76c7e07 (2026-08-07).
Data as JSON: /api/errors/d71a62099c95b45d.
Report an issue: GitHub.
Appendix: source
Thrown at infile.go:118
if idx := strings.Index(name, "Reader::"); idx == 0 || (idx > 0 && name[idx-1] == '/') { // io.Reader
// The server might return an an absolute path. See issue #355.
name = name[idx+8:]
readerRegisterLock.RLock()
handler, inMap := readerRegister[name]
readerRegisterLock.RUnlock()
if inMap {
rdr = handler()
if rdr != nil {
if cl, ok := rdr.(io.Closer); ok {
defer deferredClose(&err, cl)
}
} else {
err = fmt.Errorf("reader '%s' is <nil>", name)
}
} else {
err = fmt.Errorf("reader '%s' is not registered", name)
}
} else { // File
name = strings.Trim(name, `"`)
fileRegisterLock.RLock()
_, exists := fileRegister[name]
fileRegisterLock.RUnlock()
if mc.cfg.AllowAllFiles || exists {
var file *os.File
var fi os.FileInfo
if file, err = os.Open(name); err == nil {
defer deferredClose(&err, file)
// get file size
if fi, err = file.Stat(); err == nil {
rdr = file
if fileSize := int(fi.Size()); fileSize < packetSize {
packetSize = fileSizeView on GitHub (pinned to 03d76c7e07)