hashicorp/nomad · error

running as user %q is disallowed

Error message

running as user %q is disallowed

What it means

Nomad's validate hook enforces a user denylist for drivers on the checked_drivers list. If the task's User resolves to a user present in the configured denylist and the task's driver is one being checked, task validation fails and the task never starts. This is a security guard against running tasks as privileged or forbidden accounts.

Source

Thrown at client/allocrunner/taskrunner/validate_hook.go:57

	}

	resp.Done = true
	return nil
}

func validateTask(task *structs.Task, taskEnv *taskenv.TaskEnv, conf *config.Config) error {
	var mErr multierror.Error

	// Validate the user
	// COMPAT(1.0) uses inclusive language. blacklist is kept for backward compatilibity.
	unallowedUsers := conf.ReadStringListAlternativeToMapDefault(
		[]string{"user.denylist", "user.blacklist"},
		config.DefaultUserDenylist,
	)
	checkDrivers := conf.ReadStringListToMapDefault("user.checked_drivers", config.DefaultUserCheckedDrivers)
	if _, driverMatch := checkDrivers[task.Driver]; driverMatch {
		if _, unallowed := unallowedUsers[task.User]; unallowed {
			mErr.Errors = append(mErr.Errors, fmt.Errorf("running as user %q is disallowed", task.User))
		}
	}

	// Validate the Service names once they're interpolated
	for _, service := range task.Services {
		name := taskEnv.ReplaceEnv(service.Name)
		if err := service.ValidateName(name); err != nil {
			mErr.Errors = append(mErr.Errors, fmt.Errorf("service (%s) failed validation: %v", name, err))
		}
	}

	if len(mErr.Errors) == 1 {
		return mErr.Errors[0]
	}
	return mErr.ErrorOrNil()
}

View on GitHub (pinned to 482b49bf1a)

Solutions

  1. Change the task's user field to an allowed non-privileged user
  2. Adjust user.denylist/user.checked_drivers in the client config if policy legitimately permits the user (with caution)
  3. Remove the user block so the driver default user applies
  4. Re-run the job after fixing

Example fix

// before
task "web" {
  driver = "docker"
  user   = "root"
}
// after
task "web" {
  driver = "docker"
  user   = "nobody"
}
Defensive patterns

Strategy: validation

Validate before calling

// pre-validate the user against the denylist before submit
unallowedUsers := conf.ReadStringListToMapDefault("user.denylist", config.DefaultUserDenylist)
checkDrivers := conf.ReadStringListToMapDefault("user.checked_drivers", config.DefaultUserCheckedDrivers)
if checkDrivers[task.Driver] && unallowedUsers[task.User] {
    return fmt.Errorf("user %q disallowed for driver %q", task.User, task.Driver)
}

Try / catch

if err := validateTask(task, conf); err != nil {
    // multierror: inspect entries for the user enforcement failure
    for _, e := range err.Errors {
        if strings.Contains(e.Error(), "running as user") {
            return fmt.Errorf("fix task.user in job spec: %w", e)
        }
    }
    return err
}

Prevention

When it happens

Trigger: task.User is set (or defaults) to a user in user.denylist (default includes root) while the task's driver is in user.checked_drivers (default: docker, exec, qemu, etc.), evaluated during validateTask in Prestart.

Common situations: Jobs specifying user = "root" on docker/exec drivers; agent config where user.denylist was tightened after the job was written; legacy jobs predating the enforcement.

Related errors


AI-assisted analysis of hashicorp/nomad@482b49bf1a (2026-09-04). Data as JSON: /api/errors/66e163f6b2665e85. Report an issue: GitHub.