hashicorp/nomad · error

can't force run non-tracked job %q (%s)

Error message

can't force run non-tracked job %q (%s)

What it means

PeriodicDispatch.ForceEval was asked to force-run a periodic job that is not in the dispatcher's tracked map; the job was never added via Add (or the dispatcher was restarted/disabled and lost tracking), so it cannot be dispatched immediately.

Source

Thrown at nomad/periodic.go:299

// ForceEval causes the periodic job to be evaluated immediately and returns the
// subsequent eval.
func (p *PeriodicDispatch) ForceEval(namespace, jobID string) (*structs.Evaluation, error) {
	p.l.Lock()

	// Do nothing if not enabled
	if !p.enabled {
		p.l.Unlock()
		return nil, fmt.Errorf("periodic dispatch disabled")
	}

	tuple := structs.NamespacedID{
		ID:        jobID,
		Namespace: namespace,
	}
	job, tracked := p.tracked[tuple]
	if !tracked {
		p.l.Unlock()
		return nil, fmt.Errorf("can't force run non-tracked job %q (%s)", jobID, namespace)
	}

	p.l.Unlock()
	return p.createEval(job, time.Now().In(job.Periodic.GetLocation()))
}

// shouldRun returns whether the long lived run function should run.
func (p *PeriodicDispatch) shouldRun() bool {
	p.l.RLock()
	defer p.l.RUnlock()
	return p.enabled
}

// run is a long-lived function that waits till a job's periodic spec is met and
// then creates an evaluation to run the job.
func (p *PeriodicDispatch) run(ctx context.Context, updateCh <-chan struct{}) {
	var launchCh <-chan time.Time
	for p.shouldRun() {

View on GitHub (pinned to 482b49bf1a)

Solutions

  1. Ensure the job is registered and periodic so the dispatcher tracks it, then retry
  2. Check that the periodic dispatcher is enabled on the leader
  3. Wait for the leader to restore tracked periodic jobs after an election

Example fix

// before
job, _ := client.Jobs().Info("my-job") // job may not exist/periodic
dispatcher.ForceEval("default", *job.ID)
// after
job, _, err := client.Jobs().Info("my-job")
if err == nil && job != nil && job.IsPeriodic() {
    _, err = dispatcher.ForceEval(*job.Namespace, *job.ID)
}
Defensive patterns

Strategy: validation

Validate before calling

// Go: confirm the job is periodic and exists before ForceEval
job, _, err := client.Jobs().Info(jobID, &api.QueryOptions{Namespace: ns})
if err != nil || job == nil { return fmt.Errorf("job %q not found", jobID) }
if job.Periodic == nil { return fmt.Errorf("job %q is not periodic", jobID) }

Try / catch

// Go
if _, err := d.ForceEval(ns, jobID); err != nil {
    if strings.Contains(err.Error(), "non-tracked job") {
        return fmt.Errorf("job %s/%s is not a tracked periodic job", ns, jobID)
    }
}

Prevention

When it happens

Trigger: Calling ForceEval with a jobID/namespace that isn't in p.tracked — the job isn't periodic, doesn't exist, was deregistered, or the wrong namespace was passed.

Common situations: Typo in job ID; querying the default namespace while the job lives in another; job was deleted between listing and force-run; forcing a non-periodic job bypassing the endpoint's IsPeriodic check.

Understand the failure class

Background: "Not found" and "does not exist" errors: why "Task not found", "No such folder", and "Can't find" fire when a lookup comes back empty — this error's family across 14 libraries.

Related errors


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