{"record":{"id":"beff30051db3aa12","repo":"vitessio/vitess","slug":"invalid-argument","errorCode":"INVALID_ARGUMENT","errorMessage":"empty binlog list in ReadBinlogFilesTimestampsRequest","messagePattern":"empty binlog list in ReadBinlogFilesTimestampsRequest","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"go/vt/mysqlctl/mysqld.go","lineNumber":2207,"sourceCode":"\t\treturn nil\n\t}\n\tif err := mysqlbinlogCmd.Start(); err != nil { // Start() is nonblockig\n\t\treturn firstMatchedTime, lastMatchedTime, err\n\t}\n\tdefer mysqlbinlogCmd.Process.Kill()\n\tif err := scan(); err != nil { // We must first exhaust reading the command's output, before calling cmd.Wait()\n\t\treturn firstMatchedTime, lastMatchedTime, vterrors.Wrapf(err, \"scanning mysqlbinlog output in ReadBinlogFilesTimestamps\")\n\t}\n\tif err := mysqlbinlogCmd.Wait(); err != nil {\n\t\treturn firstMatchedTime, lastMatchedTime, vterrors.Wrapf(err, \"waiting on mysqlbinlog command in ReadBinlogFilesTimestamps\")\n\t}\n\treturn firstMatchedTime, lastMatchedTime, nil\n}\n\n// ReadBinlogFilesTimestamps reads all given binlog files via `mysqlbinlog` command and returns the first and last  found transaction timestamps\nfunc (mysqld *Mysqld) ReadBinlogFilesTimestamps(ctx context.Context, req *mysqlctlpb.ReadBinlogFilesTimestampsRequest) (*mysqlctlpb.ReadBinlogFilesTimestampsResponse, error) {\n\tif len(req.BinlogFileNames) == 0 {\n\t\treturn nil, vterrors.Errorf(vtrpcpb.Code_INVALID_ARGUMENT, \"empty binlog list in ReadBinlogFilesTimestampsRequest\")\n\t}\n\tif socketFile != \"\" {\n\t\tlog.Info(fmt.Sprintf(\"executing Mysqld.ReadBinlogFilesTimestamps() remotely via mysqlctld server: %v\", socketFile))\n\t\tclient, err := mysqlctlclient.New(ctx, \"unix\", socketFile)\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"can't dial mysqlctld: %v\", err)\n\t\t}\n\t\tdefer client.Close()\n\t\treturn client.ReadBinlogFilesTimestamps(ctx, req)\n\t}\n\tdir, err := vtenv.VtMysqlRoot()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tenv, err := buildLdPaths()\n\tif err != nil {\n\t\treturn nil, err\n\t}","sourceCodeStart":2189,"sourceCodeEnd":2225,"githubUrl":"https://github.com/vitessio/vitess/blob/01a25a7d176f94613b8d59d799f438380a8760e4/go/vt/mysqlctl/mysqld.go#L2189-L2225","documentation":"ReadBinlogFilesTimestamps validates its request before doing any work: the request must name at least one binlog file. A nil response with INVALID_ARGUMENT is returned when req.BinlogFileNames is empty, because there is nothing to scan with `mysqlbinlog`.","triggerScenarios":"Calling Mysqld.ReadBinlogFilesTimestamps(ctx, &mysqlctlpb.ReadBinlogFilesTimestampsRequest{}) or with BinlogFileNames: [] (zero-length list), either directly or via the mysqlctld RPC path.","commonSituations":"A backup/restore helper enumerating binlog files from an empty binlog directory; filtering logic that removes all files before building the request; new code paths constructing the request programmatically without checking length.","solutions":["Populate BinlogFileNames with the binlog files you want timestamps for before calling.","Guard the call site with a length check and skip the operation entirely when no files exist.","If an empty directory is legitimate, treat this error as a no-op signal rather than retrying."],"exampleFix":"// before\nres, err := mysqld.ReadBinlogFilesTimestamps(ctx, &mysqlctlpb.ReadBinlogFilesTimestampsRequest{\n\tBinlogFileNames: files,\n})\n// after\nif len(files) == 0 {\n\treturn nil // nothing to inspect\n}\nres, err := mysqld.ReadBinlogFilesTimestamps(ctx, &mysqlctlpb.ReadBinlogFilesTimestampsRequest{\n\tBinlogFileNames: files,\n})","handlingStrategy":"validation","validationCode":"if len(req.GetBinlogFileNames()) == 0 {\n\treturn fmt.Errorf(\"refusing to call ReadBinlogFilesTimestamps with no binlog files\")\n}","typeGuard":"func hasBinlogFiles(req *mysqlctlpb.ReadBinlogFilesTimestampsRequest) bool {\n\treturn req != nil && len(req.BinlogFileNames) > 0\n}","tryCatchPattern":"if !hasBinlogFiles(req) {\n\t// skip timestamps collection entirely; nothing to do\n} else if _, err := mysqld.ReadBinlogFilesTimestamps(ctx, req); err != nil {\n\treturn err\n}","preventionTips":["Check the binlog directory listing length before building the request.","Treat an empty binlog dir as a legitimate early-exit in backup/restore flows.","Add unit tests for request-construction helpers covering the empty case."],"tags":["validation","binlog","invalid-argument"],"backgroundTag":"empty-input-validation","analyzedSha":"01a25a7d176f94613b8d59d799f438380a8760e4","analyzedAt":"2026-09-01T17:28:30.605Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}