{"record":{"id":"d71a62099c95b45d","repo":"go-sql-driver/mysql","slug":"reader-s-is-not-registered","errorCode":null,"errorMessage":"reader '%s' is not registered","messagePattern":"reader '(.+?)' is not registered","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"infile.go","lineNumber":118,"sourceCode":"\tif idx := strings.Index(name, \"Reader::\"); idx == 0 || (idx > 0 && name[idx-1] == '/') { // io.Reader\n\t\t// The server might return an an absolute path. See issue #355.\n\t\tname = name[idx+8:]\n\n\t\treaderRegisterLock.RLock()\n\t\thandler, inMap := readerRegister[name]\n\t\treaderRegisterLock.RUnlock()\n\n\t\tif inMap {\n\t\t\trdr = handler()\n\t\t\tif rdr != nil {\n\t\t\t\tif cl, ok := rdr.(io.Closer); ok {\n\t\t\t\t\tdefer deferredClose(&err, cl)\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\terr = fmt.Errorf(\"reader '%s' is <nil>\", name)\n\t\t\t}\n\t\t} else {\n\t\t\terr = fmt.Errorf(\"reader '%s' is not registered\", name)\n\t\t}\n\t} else { // File\n\t\tname = strings.Trim(name, `\"`)\n\t\tfileRegisterLock.RLock()\n\t\t_, exists := fileRegister[name]\n\t\tfileRegisterLock.RUnlock()\n\t\tif mc.cfg.AllowAllFiles || exists {\n\t\t\tvar file *os.File\n\t\t\tvar fi os.FileInfo\n\n\t\t\tif file, err = os.Open(name); err == nil {\n\t\t\t\tdefer deferredClose(&err, file)\n\n\t\t\t\t// get file size\n\t\t\t\tif fi, err = file.Stat(); err == nil {\n\t\t\t\t\trdr = file\n\t\t\t\t\tif fileSize := int(fi.Size()); fileSize < packetSize {\n\t\t\t\t\t\tpacketSize = fileSize","sourceCodeStart":100,"sourceCodeEnd":136,"githubUrl":"https://github.com/go-sql-driver/mysql/blob/03d76c7e07908e255ce62d126d07ede3f2365d86/infile.go#L100-L136","documentation":"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.","triggerScenarios":"Executing \"LOAD DATA LOCAL INFILE 'Reader::data'\" without having called mysql.RegisterReaderHandler(\"data\", ...), or with a name that does not match (typo, case, prefix).","commonSituations":"Forgetting to register the handler; registering under a different name; registration living in a different init()/process.","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."],"exampleFix":"// before\ndb.Exec(\"LOAD DATA LOCAL INFILE 'Reader::data' INTO TABLE t\")\n// (no registration)\n// after\nmysql.RegisterReaderHandler(\"data\", func() io.Reader { return strings.NewReader(\"a,b\\n\") })\ndb.Exec(\"LOAD DATA LOCAL INFILE 'Reader::data' INTO TABLE t\")","handlingStrategy":"validation","validationCode":"// Verify the reader name is registered before issuing LOAD DATA.\n// (Registry is package-private; track registration in your own map.)\nif _, ok := myReaderRegistry[name]; !ok {\n    return fmt.Errorf(\"reader %q not registered\", name)\n}","typeGuard":"null","tryCatchPattern":"// The error is returned from db.Exec.\nif _, err := db.Exec(q); err != nil {\n    if strings.Contains(err.Error(), \"is not registered\") {\n        // register the reader and retry\n    }\n}","preventionTips":["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."],"tags":["go","mysql","infile","load-data"],"backgroundTag":null,"analyzedSha":"03d76c7e07908e255ce62d126d07ede3f2365d86","analyzedAt":"2026-08-07T10:39:17.340Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}