hashicorp/nomad · error

Disconnect cannot be configured with both lost_after and sto

Error message

Disconnect cannot be configured with both lost_after and stop_after

What it means

errStopAndLost is a job-validation error raised when a disconnect strategy configures both lost_after and stop_after. These fields are mutually exclusive: lost_after reconciles a disconnected client as 'lost', while stop_after stops the allocation — specifying both is ambiguous, so Validate rejects the job spec.

Source

Thrown at nomad/structs/group.go:26

	"fmt"
	"time"

	"github.com/hashicorp/go-multierror"
)

const (
	// ReconcileOption is used to specify the behavior of the reconciliation process
	// between the original allocations and the replacements when a previously
	// disconnected client comes back online.
	ReconcileOptionKeepOriginal    = "keep_original"
	ReconcileOptionKeepReplacement = "keep_replacement"
	ReconcileOptionBestScore       = "best_score"
	ReconcileOptionLongestRunning  = "longest_running"
)

var (
	// Disconnect strategy validation errors
	errStopAndLost         = errors.New("Disconnect cannot be configured with both lost_after and stop_after")
	errNegativeLostAfter   = errors.New("lost_after cannot be a negative duration")
	errNegativeStopAfter   = errors.New("stop_after cannot be a negative duration")
	errStopAfterNonService = errors.New("stop_after can only be used with service or batch job types")
	errInvalidReconcile    = errors.New("reconcile option is invalid")
)

func NewDefaultDisconnectStrategy() *DisconnectStrategy {
	return &DisconnectStrategy{
		Replace:   new(true),
		Reconcile: ReconcileOptionBestScore,
	}
}

// Disconnect strategy defines how both clients and server should behave in case of
// disconnection between them.
type DisconnectStrategy struct {
	// Defines for how long the server will consider the unresponsive node as
	// disconnected but alive instead of lost.

View on GitHub (pinned to 482b49bf1a)

Solutions

  1. Remove either lost_after or stop_after from the disconnect block, keeping the behavior you want
  2. If the desired behavior is 'reconcile as lost', set only lost_after and delete stop_after
  3. If the desired behavior is 'stop the task', set only stop_after and delete lost_after
  4. Run 'nomad job validate <file>' before submitting to catch the conflict early

Example fix

// before
disconnect {
  lost_after  = "2h"
  stop_after  = "30m"
}
// after
disconnect {
  stop_after = "30m"
}
Defensive patterns

Strategy: validation

Validate before calling

if ds := grp.Disconnect; ds != nil && ds.LostAfter > 0 && ds.StopOnClientAfter != nil {
    return fmt.Errorf("disconnect: set only one of lost_after or stop_after")
}

Type guard

func hasConflictingDisconnect(ds *api.DisconnectStrategy) bool {
    return ds != nil && ds.LostAfter > 0 && ds.StopOnClientAfter != nil
}

Try / catch

err := client.Jobs().Validate(job, nil, nil)
if err != nil && strings.Contains(err.Error(), "both lost_after and stop_after") {
    return fmt.Errorf("fix job spec: remove either lost_after or stop_after: %w", err)
}

Prevention

When it happens

Trigger: Submitting a job (Job.Validate / job register or plan) whose group's disconnect block sets both lost_after (> 0) and stop_after (non-nil), checked at group.go:88 in DisconnectStrategy.Validate.

Common situations: Merging HCL/JSON fragments where one file sets lost_after and another sets stop_after; upgrading a job spec written for an older Nomad (only lost_after existed) and adding stop_after without removing lost_after; copy-paste of example disconnect configs.

Related errors


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