hashicorp/nomad · error
launch not found
Error message
launch not found
What it means
Returned by StateStore.DeletePeriodicLaunchTxn when no PeriodicLaunch record exists for the given (namespace, jobID). The launch bookkeeping (last launched time for a periodic job) is absent, so there is nothing to delete and the caller's intent is invalid.
Source
Thrown at nomad/state/state_store.go:3391
defer txn.Abort()
err := s.DeletePeriodicLaunchTxn(index, namespace, jobID, txn)
if err == nil {
return txn.Commit()
}
return err
}
// DeletePeriodicLaunchTxn is used to delete the periodic launch, like DeletePeriodicLaunch
// but in a transaction. Useful for when making multiple modifications atomically
func (s *StateStore) DeletePeriodicLaunchTxn(index uint64, namespace, jobID string, txn Txn) error {
// Lookup the launch
existing, err := txn.First("periodic_launch", "id", namespace, jobID)
if err != nil {
return fmt.Errorf("launch lookup failed: %v", err)
}
if existing == nil {
return fmt.Errorf("launch not found")
}
// Delete the launch
if err := txn.Delete("periodic_launch", existing); err != nil {
return fmt.Errorf("launch delete failed: %v", err)
}
if err := txn.Insert("index", &IndexEntry{"periodic_launch", index}); err != nil {
return fmt.Errorf("index update failed: %v", err)
}
return nil
}
// PeriodicLaunchByID is used to lookup a periodic launch by the periodic job
// ID.
func (s *StateStore) PeriodicLaunchByID(ws memdb.WatchSet, namespace, id string) (*structs.PeriodicLaunch, error) {
txn := s.db.ReadTxn()
View on GitHub (pinned to 482b49bf1a)
Solutions
- Treat this as an idempotency signal: if the job is already gone, log and return success instead of erroring
- Verify the namespace and job ID match the registered periodic job (use job list / job inspect)
- Ensure the job was actually registered as periodic before deleting its launch record
- Check for duplicate delete calls in your automation (e.g. retries after a successful delete)
Example fix
// before
if err := state.DeletePeriodicLaunch(100, "default", "my-periodic"); err != nil {
return err
}
// after
if err := state.DeletePeriodicLaunch(100, "default", "my-periodic"); err != nil {
if strings.Contains(err.Error(), "launch not found") {
return nil // already deleted; idempotent
}
return err
} Defensive patterns
Strategy: validation
Validate before calling
launch, err := state.PeriodicLaunchByID(ws, namespace, jobID)
if err != nil { return err }
if launch == nil {
// already deleted or never launched: skip delete
return nil
} Type guard
if l, ok := existing.(*structs.PeriodicLaunch); !ok || l == nil { return nil } Try / catch
if err := state.DeletePeriodicLaunch(idx, ns, jobID); err != nil {
if strings.Contains(err.Error(), "launch not found") {
return nil // idempotent success
}
return err
} Prevention
- Check existence with PeriodicLaunchByID before delete
- Make delete flows idempotent (treat not-found as success)
- Guard against double deletes from retries in automation
When it happens
Trigger: Calling DeletePeriodicLaunch(index, namespace, jobID) for a job ID that never had UpsertPeriodicLaunch called, or for a job that was already deleted (or whose launch was already removed), e.g. deleting a periodic job twice.
Common situations: Deregistering a periodic job whose launch entry was already cleaned up by a prior delete or job purge; stale job IDs from an older namespace; calling delete with namespace/jobID swapped.
Understand the failure class
Background: 'Could not be found', 'does not exist', 'not found in database': the resource-not-found family when an ID, slug, key, or URI lookup comes back empty — this error's family across 20 libraries.
Related errors
- eval not found
- variable doesn't exist
- unknown deployment %q
- job %q not found
- periodic launch lookup failed: %v
AI-assisted analysis of hashicorp/nomad@482b49bf1a (2026-09-04).
Data as JSON: /api/errors/7194c7f60aea2b4d.
Report an issue: GitHub.