projectdiscovery/nuclei · error
could not read profile file: %w
Error message
could not read profile file: %w
What it means
processInlineSecretsFromProfile (cmd/nuclei/main.go:880) reads the profile file with os.ReadFile before extracting its `secrets:` section; any read failure is wrapped as 'could not read profile file' with the os error (%w) carrying the exact cause (ENOENT, EACCES, is-a-directory, etc.). It fires at startup when a profile is supplied, before any scanning starts.
Source
Thrown at cmd/nuclei/main.go:880
})
if err != nil && err.Error() != "FOUND" {
options.Logger.Error().Msgf("%s\n", err)
}
return profilePath
}
// profileSecrets is a helper struct to extract secrets section from a template profile YAML
type profileSecrets struct {
Secrets interface{} `yaml:"secrets"`
}
// processInlineSecretsFromProfile parses the profile YAML file for inline secrets
// and creates a temporary secrets file compatible with nuclei's auth provider.
// Returns the path to the temp file or empty string if no secrets found.
func processInlineSecretsFromProfile(profilePath string, options *types.Options) (string, error) {
data, err := os.ReadFile(profilePath)
if err != nil {
return "", fmt.Errorf("could not read profile file: %w", err)
}
var profile profileSecrets
if err := yaml.Unmarshal(data, &profile); err != nil {
return "", fmt.Errorf("could not parse profile YAML: %w", err)
}
if profile.Secrets == nil {
return "", nil
}
secretsData, err := yaml.Marshal(profile.Secrets)
if err != nil {
return "", fmt.Errorf("could not marshal inline secrets: %w", err)
}
tempDir := filepath.Join(os.TempDir(), "nuclei-secrets")
if err := os.MkdirAll(tempDir, 0700); err != nil {View on GitHub (pinned to 265b3a3dec)
Solutions
- Confirm the path exists and is a regular file (`ls -l <path>`)
- Use an absolute path for the profile file
- Fix readability (ownership/chmod) or copy the profile somewhere readable
- In containers, verify the volume actually mounts the profile at that path
Example fix
# before nuclei -profile profiles/scan.yaml # after ls -l /home/user/profiles/scan.yaml nuclei -profile /home/user/profiles/scan.yaml
Defensive patterns
Strategy: validation
Validate before calling
if fi, err := os.Stat(profilePath); err != nil || fi.IsDir() {
return fmt.Errorf("profile path %q missing or not a file", profilePath)
}
// optional readability probe
if f, err := os.Open(profilePath); err != nil {
return fmt.Errorf("profile not readable: %w", err)
} else { _ = f.Close() } Try / catch
data, err := os.ReadFile(profilePath)
if err != nil {
if errors.Is(err, fs.ErrNotExist) {
return fmt.Errorf("profile %s does not exist", profilePath)
}
if errors.Is(err, fs.ErrPermission) {
return fmt.Errorf("profile %s not readable by uid %d", profilePath, os.Getuid())
}
return err
} Prevention
- Use absolute profile paths in scripts and CI
- Check existence and readability of the profile before launching nuclei
- Mount/verify profile files explicitly in containers
When it happens
Trigger: Running nuclei with a `-profile` path that does not exist, is a directory, or is unreadable by the current user; a relative profile path resolved from a different working directory.
Common situations: Typo'd profile path; profile created by root/another user with restrictive permissions; containers/CI where the profile file was not mounted at the expected path.
Related errors
- include directive preprocessing is disabled
- could not parse profile YAML: %w
- could not create temp directory: %w
- aws s3 bucket details are missing. Please provide %s
- azure connection details are missing. Please provide %s
AI-assisted analysis of projectdiscovery/nuclei@265b3a3dec (2026-08-15).
Data as JSON: /api/errors/2be38fced2e77d32.
Report an issue: GitHub.