{"record":{"id":"fe09c4ba2c91bb6e","repo":"Netflix/chaosmonkey","slug":"unknown-group-v","errorCode":null,"errorMessage":"unknown group: %v","messagePattern":"unknown group: (.+?)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"mysql/mysql.go","lineNumber":326,"sourceCode":"\t\treturn err\n\t}\n\tquery := \"SELECT instance_id, killed_at FROM terminations WHERE app = ? AND account = ? AND killed_at >= ?\"\n\n\tvar rows *sql.Rows\n\n\targs := []interface{}{app, account, threshold.In(time.UTC)}\n\n\tswitch appCfg.Grouping {\n\tcase chaosmonkey.App:\n\t\t// nothing to do\n\tcase chaosmonkey.Stack:\n\t\tquery += \" AND stack = ?\"\n\t\targs = append(args, term.Instance.StackName())\n\tcase chaosmonkey.Cluster:\n\t\tquery += \" AND cluster = ?\"\n\t\targs = append(args, term.Instance.ClusterName())\n\tdefault:\n\t\treturn errors.Errorf(\"unknown group: %v\", appCfg.Grouping)\n\t}\n\n\tif appCfg.RegionsAreIndependent {\n\t\tquery += \" AND region = ?\"\n\t\targs = append(args, term.Instance.RegionName())\n\t}\n\n\t// For unleashed (real) terminations, we only care about previous\n\t// terminations that were also unleashed. That's because a previous\n\t// leashed termination wasn't a real one, so that wouldn't violate\n\t// the min time between terminations\n\tif !term.Leashed {\n\t\tquery += \" AND leashed = FALSE\"\n\t}\n\n\t// We need at most one entry\n\tquery += \" LIMIT 1\"\n","sourceCodeStart":308,"sourceCodeEnd":344,"githubUrl":"https://github.com/Netflix/chaosmonkey/blob/eaa28fb761c0ebe8644d1333e5d164e9cc3071e9/mysql/mysql.go#L308-L344","documentation":"respectsMinTimeBetweenKills builds a SQL query to check the minimum time between kills, appending a WHERE clause based on appCfg.Grouping. If the grouping value is not App, Stack, or Cluster, it falls through to default and returns 'unknown group: %v'. Only the three known grouping modes are supported.","triggerScenarios":"An AppConfig whose Grouping field holds a value other than chaosmonkey.App, chaosmonkey.Stack, or chaosmonkey.Cluster reaches CheckWithDelay → respectsMinTimeBetweenKills.","commonSituations":"Config file containing an invalid grouping string (e.g. 'region', typo like 'stacks') that deserializes into an out-of-range value; a schema/config version change introducing a new grouping not yet supported by the MySQL layer.","solutions":["Set app.grouping in the config to one of: app, stack, cluster","Log/validate appCfg.Grouping at config load time and reject unknown values early","If a new grouping mode is intended, add a case for it in respectsMinTimeBetweenKills' switch","Check for merge/schema changes that altered the Grouping enum values"],"exampleFix":"// before (config)\napp:\n  grouping: \"region\"\n// after\napp:\n  grouping: \"cluster\"","handlingStrategy":"validation","validationCode":"switch cfg.App().Grouping {\ncase chaosmonkey.App, chaosmonkey.Stack, chaosmonkey.Cluster:\n    // ok\ndefault:\n    return fmt.Errorf(\"invalid app.grouping %v; must be app, stack, or cluster\", cfg.App().Grouping)\n}","typeGuard":"func groupingSupported(g chaosmonkey.Grouping) bool {\n    switch g {\n    case chaosmonkey.App, chaosmonkey.Stack, chaosmonkey.Cluster:\n        return true\n    }\n    return false\n}","tryCatchPattern":"if err := monkey.CheckWithDelay(ctx, app); err != nil {\n    if strings.Contains(err.Error(), \"unknown group\") {\n        log.Printf(\"grouping %q not supported by storage layer\", cfg.Grouping())\n    }\n}","preventionTips":["Restrict grouping config to the documented enum values (app, stack, cluster)","Validate grouping at config load time, before any DB access","Add a unit test covering each supported grouping through respectsMinTimeBetweenKills"],"tags":["go","mysql","configuration","grouping"],"backgroundTag":"unsupported-enum-value","analyzedSha":"eaa28fb761c0ebe8644d1333e5d164e9cc3071e9","analyzedAt":"2026-09-03T17:04:39.020Z","contentChangedAt":"2026-09-03T17:04:39.020Z","schemaVersion":2},"datasetVersion":"2026-09-08T15:18:49.778Z"}