{"record":{"id":"73806a2bfe0b9164","repo":"grafana/k6","slug":"the-gracefulstop-timeout-can-t-be-negative","errorCode":null,"errorMessage":"the gracefulStop timeout can't be negative","messagePattern":"the gracefulStop timeout can't be negative","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"lib/executor/base_config.go","lineNumber":70,"sourceCode":"\t// even assigned by us:\n\tif bc.Name == \"\" {\n\t\tresult = append(result, errors.New(\"scenario name can't be empty\"))\n\t}\n\tif !scenarioNameWhitelist.MatchString(bc.Name) {\n\t\tresult = append(result, errors.New(scenarioNameErr))\n\t}\n\tif bc.Exec.Valid && bc.Exec.String == \"\" {\n\t\tresult = append(result, errors.New(\"exec value cannot be empty\"))\n\t}\n\tif bc.Type == \"\" {\n\t\tresult = append(result, errors.New(\"missing or empty type field\"))\n\t}\n\t// The actually reasonable checks:\n\tif bc.StartTime.Duration < 0 {\n\t\tresult = append(result, errors.New(\"the startTime can't be negative\"))\n\t}\n\tif bc.GracefulStop.Duration < 0 {\n\t\tresult = append(result, errors.New(\"the gracefulStop timeout can't be negative\"))\n\t}\n\treturn result\n}\n\n// GetName returns the name of the scenario.\nfunc (bc BaseConfig) GetName() string {\n\treturn bc.Name\n}\n\n// GetType returns the executor's type as a string ID.\nfunc (bc BaseConfig) GetType() string {\n\treturn bc.Type\n}\n\n// GetStartTime returns the starting time, relative to the beginning of the\n// actual test, that this executor is supposed to execute.\nfunc (bc BaseConfig) GetStartTime() time.Duration {\n\treturn bc.StartTime.TimeDuration()","sourceCodeStart":52,"sourceCodeEnd":88,"githubUrl":"https://github.com/grafana/k6/blob/93accf6570dcd306ca5e99cc44c393ee3797761b/lib/executor/base_config.go#L52-L88","documentation":"Emitted by BaseConfig.Validate (lib/executor/base_config.go:69-71) when a scenario's gracefulStop is negative. gracefulStop (types.NullDuration) is how long k6 waits for already-running iterations to finish at the end of a scenario before forcibly stopping them (default 30s, DefaultGracefulStopValue at line 20). A negative grace period is meaningless and rejected.","triggerScenarios":"Setting scenarios: { smoke: { executor: 'constant-vus', gracefulStop: '-1s', ... } } or any config where the gracefulStop duration string parses negative. Only fires when the field is set, since the default set by NewBaseConfig is valid but not Valid (null), and negative durations always have Duration < 0.","commonSituations":"Attempting to express 'no graceful stop' with a negative value; the correct expression is gracefulStop: '0s'. Sign typos in generated configs also hit this.","solutions":["Use gracefulStop: '0s' to disable the grace period entirely","Or use a positive value like '30s' (default) or '1m' for longer iteration wind-down"],"exampleFix":"// before\nexport const options = {\n  scenarios: { s: { executor: 'constant-vus', gracefulStop: '-1s', vus: 1, duration: '10s' } },\n};\n\n// after\nexport const options = {\n  scenarios: { s: { executor: 'constant-vus', gracefulStop: '0s', vus: 1, duration: '10s' } },\n};","handlingStrategy":"validation","validationCode":"// If 'no graceful stop' is intended, normalize to '0s'\nconst gs = __ENV.GRACEFUL_STOP || '30s';\nif (gs.startsWith('-')) throw new Error('gracefulStop must be >= 0; use 0s to disable');","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Use gracefulStop: '0s' to disable iteration wind-down, never a negative value","Review generated scenario configs for sign errors on duration fields"],"tags":["config","scenarios","gracefulstop","validation"],"backgroundTag":null,"analyzedSha":"93accf6570dcd306ca5e99cc44c393ee3797761b","analyzedAt":"2026-08-15T21:23:27.118Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}