{"record":{"id":"1ed62705ae27a7a0","repo":"hashicorp/nomad","slug":"maxparallel-must-be-0-but-found-d","errorCode":null,"errorMessage":"MaxParallel must be >= 0 but found %d","messagePattern":"MaxParallel must be >= 0 but found (.+?)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"nomad/structs/structs.go","lineNumber":6840,"sourceCode":"\n// DefaultMigrateStrategy is used for backwards compat with pre-0.8 Allocations\n// that lack an update strategy.\n//\n// This function should match its counterpart in api/tasks.go\nfunc DefaultMigrateStrategy() *MigrateStrategy {\n\treturn &MigrateStrategy{\n\t\tMaxParallel:     1,\n\t\tHealthCheck:     MigrateStrategyHealthChecks,\n\t\tMinHealthyTime:  10 * time.Second,\n\t\tHealthyDeadline: 5 * time.Minute,\n\t}\n}\n\nfunc (m *MigrateStrategy) Validate() error {\n\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 {","sourceCodeStart":6822,"sourceCodeEnd":6858,"githubUrl":"https://github.com/hashicorp/nomad/blob/482b49bf1aec006f089bcfc7e632d8f6ac303e5e/nomad/structs/structs.go#L6822-L6858","documentation":"MigrateStrategy.Validate rejects a negative MaxParallel. MaxParallel controls how many allocations may be migrated concurrently during deployments; a negative value is meaningless and indicates a config error. The error is appended to the strategy's multierror and returned during job validation.","triggerScenarios":"Submitting a job with a task group update block where update.max_parallel is explicitly negative (e.g. max_parallel = -1), typically from templating math or variables that evaluate negative.","commonSituations":"Templated job files where a computed concurrency value goes negative; mistaken belief that -1 means 'unlimited' (in Nomad, 0 means no migrations during deploy); migration from other orchestrators where -1 signals infinity.","solutions":["Set max_parallel to 0 or a positive integer (0 means migrate none during deployment).","If 'unlimited' was intended, use a large positive value; Nomad has no -1 = infinite semantics for max_parallel.","Fix the templating expression producing the negative number.","Validate with `nomad job validate` before submitting."],"exampleFix":"// before\nupdate {\n  max_parallel = -1\n}\n// after\nupdate {\n  max_parallel = 1\n}","handlingStrategy":"validation","validationCode":"func validMaxParallel(m *structs.MigrateStrategy) error {\n\tif m.MaxParallel < 0 {\n\t\treturn fmt.Errorf(\"max_parallel must be >= 0, got %d\", m.MaxParallel)\n\t}\n\treturn nil\n}","typeGuard":"func hasNonNegativeMaxParallel(m *structs.MigrateStrategy) bool {\n\treturn m.MaxParallel >= 0\n}","tryCatchPattern":"if err := strategy.Validate(); err != nil {\n\tif strings.Contains(err.Error(), \"MaxParallel must be >= 0\") {\n\t\t// clamp to 0 or positive before resubmit\n\t}\n}","preventionTips":["Clamp computed max_parallel to >= 0 in templates.","Remember 0 (not -1) means 'no migrations during deploy' in Nomad.","Sanitize external inputs feeding max_parallel.","Validate update blocks in CI before job submission."],"tags":["nomad","go","validation","migrate-strategy","deployment"],"backgroundTag":"negative-integer-config-validation","analyzedSha":"482b49bf1aec006f089bcfc7e632d8f6ac303e5e","analyzedAt":"2026-09-04T07:54:14.808Z","contentChangedAt":"2026-09-04T07:54:14.808Z","schemaVersion":2},"datasetVersion":"2026-09-08T15:18:49.778Z"}