{"record":{"id":"3ceed79d93cfe186","repo":"hashicorp/nomad","slug":"minhealthytime-is-s-and-must-be-0","errorCode":null,"errorMessage":"MinHealthyTime is %s and must be >= 0","messagePattern":"MinHealthyTime is (.+?) and must be >= 0","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"nomad/structs/structs.go","lineNumber":6855,"sourceCode":"\tvar mErr multierror.Error\n\n\tif m.MaxParallel < 0 {\n\t\t_ = multierror.Append(&mErr, fmt.Errorf(\"MaxParallel must be >= 0 but found %d\", m.MaxParallel))\n\t}\n\n\tswitch m.HealthCheck {\n\tcase MigrateStrategyHealthChecks, MigrateStrategyHealthStates:\n\t\t// ok\n\tcase \"\":\n\t\tif m.MaxParallel > 0 {\n\t\t\t_ = multierror.Append(&mErr, fmt.Errorf(\"Missing HealthCheck\"))\n\t\t}\n\tdefault:\n\t\t_ = multierror.Append(&mErr, fmt.Errorf(\"Invalid HealthCheck: %q\", m.HealthCheck))\n\t}\n\n\tif m.MinHealthyTime < 0 {\n\t\t_ = multierror.Append(&mErr, fmt.Errorf(\"MinHealthyTime is %s and must be >= 0\", m.MinHealthyTime))\n\t}\n\n\tif m.HealthyDeadline < 0 {\n\t\t_ = multierror.Append(&mErr, fmt.Errorf(\"HealthyDeadline is %s and must be >= 0\", m.HealthyDeadline))\n\t}\n\n\tif m.MinHealthyTime > m.HealthyDeadline {\n\t\t_ = multierror.Append(&mErr, fmt.Errorf(\"MinHealthyTime must be less than HealthyDeadline\"))\n\t}\n\n\treturn mErr.ErrorOrNil()\n}\n\n// TaskGroup is an atomic unit of placement. Each task group belongs to\n// a job and may contain any number of tasks. A task group support running\n// in many replicas using the same configuration..\ntype TaskGroup struct {\n\t// Name of the task group","sourceCodeStart":6837,"sourceCodeEnd":6873,"githubUrl":"https://github.com/hashicorp/nomad/blob/482b49bf1aec006f089bcfc7e632d8f6ac303e5e/nomad/structs/structs.go#L6837-L6873","documentation":"MigrateStrategy.Validate rejects a negative MinHealthyTime. MinHealthyTime is how long an allocation must be healthy before it counts toward the healthy threshold during migration; negative durations are invalid. This is a straightforward non-negativity guard in the strategy validator.","triggerScenarios":"Submitting a job with update block where min_healthy_time is negative (e.g. min_healthy_time = \"-5s\"), typically from templating or bad parsing of durations.","commonSituations":"Templated durations computed from negative inputs; accidental sign in HCL; misconfigured defaults in generated job specs.","solutions":["Set min_healthy_time to a non-negative duration (e.g. \"30s\", the common default).","Fix any template expression producing a negative duration.","Omit the field to rely on sane defaults if your tooling allows.","Validate locally with `nomad job validate`."],"exampleFix":"// before\nupdate {\n  min_healthy_time = \"-5s\"\n}\n// after\nupdate {\n  min_healthy_time = \"30s\"\n}","handlingStrategy":"validation","validationCode":"func validMinHealthyTime(m *structs.MigrateStrategy) error {\n\tif m.MinHealthyTime < 0 {\n\t\treturn fmt.Errorf(\"min_healthy_time must be >= 0, got %s\", m.MinHealthyTime)\n\t}\n\treturn nil\n}","typeGuard":"func hasNonNegativeMinHealthyTime(m *structs.MigrateStrategy) bool {\n\treturn m.MinHealthyTime >= 0\n}","tryCatchPattern":"if err := strategy.Validate(); err != nil {\n\tif strings.Contains(err.Error(), \"MinHealthyTime is\") {\n\t\t// reset min_healthy_time to a non-negative default like 30s\n\t}\n}","preventionTips":["Clamp templated durations to >= 0.","Avoid computing durations from potentially negative inputs.","Use explicit unit suffixes in HCL to prevent parse surprises.","Gate job specs with `nomad job validate` in CI."],"tags":["nomad","go","validation","migrate-strategy","duration"],"backgroundTag":"negative-duration-validation","analyzedSha":"482b49bf1aec006f089bcfc7e632d8f6ac303e5e","analyzedAt":"2026-09-04T07:54:14.808Z","contentChangedAt":"2026-09-04T07:54:14.808Z","schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}