hashicorp/nomad · error
intro token file is a directory
Error message
intro token file is a directory
What it means
After stat succeeds, readIntroTokenFile checks fileStat.IsDir(); if the intro token path is a directory, it returns this plain error because a directory cannot hold token content. The intro token must be a regular file whose contents are the token.
Source
Thrown at command/agent/agent.go:879
rootFile, err := os.OpenInRoot(cfg.StateDir, "intro_token.jwt")
if err != nil {
if os.IsNotExist(err) {
return nil
}
return err
}
fileStat, err := rootFile.Stat()
if err != nil {
return fmt.Errorf("failed to stat intro token file: %w", err)
}
// If the file exists and is a file, attempt to read the contents and set
// the intro token. Any error is logged for the operator to investigate but
// does not block the agent from starting.
if fileStat.IsDir() {
return fmt.Errorf("intro token file is a directory")
}
content, err := helper.ReadFileContent(rootFile)
if err != nil {
return fmt.Errorf("failed to read intro token file: %w", err)
}
cfg.IntroToken = strings.TrimSpace(string(content))
return nil
}
// convertClientConfig takes an agent config and log output and returns a client
// Config. There may be missing fields that must be set by the agent. To do this
// call finalizeServerConfig
func convertClientConfig(agentConfig *Config) (*clientconfig.Config, error) {
// Set up the configuration
conf := agentConfig.ClientConfig
if conf == nil {View on GitHub (pinned to 482b49bf1a)
Solutions
- Point intro_token_file at the actual regular file, not its parent directory.
- For volume-mounted secrets, reference the key file inside the mount (e.g. /secrets/intro-token, not /secrets).
- Pre-provision a file at the path if the mount point is a directory by design.
Example fix
// before
client { intro_token_file = "/var/run/secrets/nomad" } // directory
// after
client { intro_token_file = "/var/run/secrets/nomad/intro-token" } Defensive patterns
Strategy: validation
Validate before calling
fi, err := os.Stat(path)
if err != nil {
return err
}
if fi.IsDir() {
return fmt.Errorf("intro_token_file %q is a directory; point to the token file itself", path)
} Prevention
- Reference the key file inside mounted secret volumes, not the mount root.
- Add a pre-start check that the path is a regular file (fi.Mode().IsRegular()).
- Avoid directory-typed config variables for file paths.
When it happens
Trigger: client.intro_token_file pointing at a directory (e.g. a secrets mount point like /var/run/secrets/ or the token's parent directory instead of the file), invoked from finalizeClientConfig.
Common situations: Kubernetes secret volume mounts where the user gives the volume dir rather than the key file inside it; path expansion mistakes in config tooling; mounted paths that are always directories.
Related errors
- plugin not found
- plugin not executable
- wait config is nil or empty
- wait config is empty
- ErrPluginNotExists
AI-assisted analysis of hashicorp/nomad@482b49bf1a (2026-09-04).
Data as JSON: /api/errors/75aa22463c1e7cae.
Report an issue: GitHub.