{"record":{"id":"80901040d2837383","repo":"projectdiscovery/nuclei","slug":"file-path-cannot-be-empty","errorCode":null,"errorMessage":"file path cannot be empty","messagePattern":"file path cannot be empty","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/js/libs/smbsession/session.go","lineNumber":222,"sourceCode":"\t\t}\n\t\tout = append(out, fileInfoToEntry(fi))\n\t}\n\treturn out, nil\n}\n\nfunc readFile(ops shareBackend, share, filePath string, maxBytes int64) (string, error) {\n\tif err := RequireShareName(share); err != nil {\n\t\treturn \"\", err\n\t}\n\tif maxBytes <= 0 {\n\t\tmaxBytes = DefaultMaxReadBytes\n\t}\n\tnormalized, err := NormalizeSharePath(filePath)\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\tif normalized == \".\" {\n\t\treturn \"\", fmt.Errorf(\"file path cannot be empty\")\n\t}\n\tif err := ops.UseShare(share); err != nil {\n\t\treturn \"\", fmt.Errorf(\"mount share %q: %w\", share, err)\n\t}\n\t// Prefer streaming Open+LimitReader when the backend supports it (tests /\n\t// future goimpacket Open). Fall back to Cat for the stock client.\n\tif opener, ok := ops.(shareOpener); ok {\n\t\tf, err := opener.Open(normalized)\n\t\tif err != nil {\n\t\t\treturn \"\", err\n\t\t}\n\t\tdefer func() { _ = f.Close() }()\n\t\tlimited := io.LimitReader(f, maxBytes+1)\n\t\tbody, err := io.ReadAll(limited)\n\t\tif err != nil {\n\t\t\treturn \"\", err\n\t\t}\n\t\tif int64(len(body)) > maxBytes {","sourceCodeStart":204,"sourceCodeEnd":240,"githubUrl":"https://github.com/projectdiscovery/nuclei/blob/265b3a3dec374741614e342f813c10f8b38d2bb7/pkg/js/libs/smbsession/session.go#L204-L240","documentation":"Thrown by readFile in the smbsession library when the normalized file path is \".\" — i.e. the path argument resolves to the share root instead of a file. NormalizeSharePath collapses empty strings, \".\", and \"./\" to \".\", and reading the root itself is not a file read, so the library rejects it explicitly before touching the network.","triggerScenarios":"Calling ReadFile(share, '') or ReadFile(share, '.'); building the path from a variable that is empty due to a failed extract or missing variable interpolation; passing './' expecting the root directory listing.","commonSituations":"Templates that read a path extracted from a previous step where the extractor matched nothing; default parameter values left as empty strings; confusion between ReadFile and ListTree for directory content.","solutions":["Pass a concrete non-empty file path such as '/windows/win.ini'","If the path comes from a variable, verify the extractor/population step produced a value before calling ReadFile","Use ListTree/ListDir to list a directory instead of ReadFile"],"exampleFix":"// before\nconst data = client.ReadFile('C$', path, 0); // path is ''\n\n// after\nif (path && path !== '.' && path !== './') {\n  const data = client.ReadFile('C$', path, 0);\n}","handlingStrategy":"validation","validationCode":"function isRealFilePath(p) { return typeof p === 'string' && p.trim() !== '' && p !== '.' && p !== './'; }\nif (isRealFilePath(filePath)) { client.ReadFile(share, filePath, 0); }","typeGuard":"function isRealFilePath(p) { return typeof p === 'string' && p.trim() !== '' && p.trim() !== '.'; }","tryCatchPattern":"try { client.ReadFile(share, p, 0) } catch (e) { if (String(e).includes('file path cannot be empty')) { /* skip empty target */ } else { throw e; } }","preventionTips":["Guard paths sourced from extractors before reading","Default to a concrete well-known file path","Use ListTree for directories, never ReadFile"],"tags":["smb","javascript","nuclei","input-validation"],"backgroundTag":null,"analyzedSha":"265b3a3dec374741614e342f813c10f8b38d2bb7","analyzedAt":"2026-08-15T20:05:51.855Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}