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

  1. Register the handler with mysql.RegisterReaderHandler using the exact name that appears in the SQL.
  2. Check for typos, case, and the 'Reader::' prefix between the SQL string and the registration call.
  3. 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

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


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 = fileSize

View on GitHub (pinned to 03d76c7e07)