{"record":{"id":"fb3b1badbd3fe997","repo":"go-sql-driver/mysql","slug":"local-file-s-is-not-registered","errorCode":null,"errorMessage":"local file '%s' is not registered","messagePattern":"local file '(.+?)' is not registered","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"infile.go","lineNumber":141,"sourceCode":"\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\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t} else {\n\t\t\terr = fmt.Errorf(\"local file '%s' is not registered\", name)\n\t\t}\n\t}\n\n\t// send content packets\n\tvar data []byte\n\n\t// if packetSize == 0, the Reader contains no data\n\tif err == nil && packetSize > 0 {\n\t\tdata = make([]byte, 4+packetSize)\n\t\tvar n int\n\t\tfor err == nil {\n\t\t\tn, err = rdr.Read(data[4:])\n\t\t\tif n > 0 {\n\t\t\t\tif ioErr := mc.conn().writePacket(data[:4+n]); ioErr != nil {\n\t\t\t\t\treturn ioErr\n\t\t\t\t}\n\t\t\t}\n\t\t}","sourceCodeStart":123,"sourceCodeEnd":159,"githubUrl":"https://github.com/go-sql-driver/mysql/blob/03d76c7e07908e255ce62d126d07ede3f2365d86/infile.go#L123-L159","documentation":"For plain file paths in LOAD DATA LOCAL INFILE (not Reader::), the driver requires the file be on its allowlist (mysql.RegisterLocalFile) OR the DSN set allowAllFiles=true. Without either, it refuses to read the file from the client machine for security.","triggerScenarios":"Executing \"LOAD DATA LOCAL INFILE '/path/file.csv'\" without mysql.RegisterLocalFile(\"/path/file.csv\") and without '?allowAllFiles=true' in the DSN.","commonSituations":"Forgetting the security allowlist; path mismatch (the server may return an absolute path while you registered a relative one, or vice-versa); default-deny surprising new developers.","solutions":["Register the exact path with mysql.RegisterLocalFile before the Exec, matching the path the server echoes (it may absolutize it).","Set '?allowAllFiles=true' in the DSN only in trusted environments where you accept reading any client-side file.","Ensure the path matches exactly (quotes are trimmed by the driver; watch absolute vs relative)."],"exampleFix":"// before\ndb.Exec(\"LOAD DATA LOCAL INFILE '/tmp/data.csv' INTO TABLE t\")\n// after (option A: allowlist)\nmysql.RegisterLocalFile(\"/tmp/data.csv\")\ndb.Exec(\"LOAD DATA LOCAL INFILE '/tmp/data.csv' INTO TABLE t\")\n// after (option B: allow all, trusted only)\nsql.Open(\"mysql\", \"user@tcp(127.0.0.1:3306)/db?allowAllFiles=true\")","handlingStrategy":"validation","validationCode":"// Track which files you allowlisted; match the path used in SQL.\nfunc isAllowed(p string) bool {\n    abs, _ := filepath.Abs(p)\n    _, ok := allowedFiles[abs]\n    return ok\n}","typeGuard":"null","tryCatchPattern":"// Surface from Exec and guide the user to register or enable allowAllFiles.\nif _, err := db.Exec(q); err != nil {\n    if strings.Contains(err.Error(), \"is not registered\") {\n        mysql.RegisterLocalFile(path) // then retry once\n    }\n}","preventionTips":["Prefer RegisterLocalFile over allowAllFiles for least privilege.","Register the absolute path to match what the server echoes.","Avoid allowAllFiles=true in shared/untrusted environments."],"tags":["go","mysql","infile","security","load-data"],"backgroundTag":null,"analyzedSha":"03d76c7e07908e255ce62d126d07ede3f2365d86","analyzedAt":"2026-08-07T10:39:17.340Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}