{"record":{"id":"e7b309c4d154b604","repo":"nodejs/node","slug":"invalid-suite-configuration-s","errorCode":null,"errorMessage":"Invalid suite configuration.%s","messagePattern":"Invalid suite configuration\\.(.+?)","errorType":"exception","errorClass":"Exception","httpStatus":null,"severity":"error","filePath":"deps/v8/tools/run_perf.py","lineNumber":656,"sourceCode":"def GetGraphConfigClass(suite, parent):\n  \"\"\"Factory method for making graph configuration objects.\"\"\"\n  if isinstance(parent, TraceConfig):\n    if suite.get(\"tests\"):\n      return TraceConfig\n    return LeafTraceConfig\n  elif suite.get('main') is not None:\n    # A main file makes this graph runnable. Empty strings are accepted.\n    if suite.get('tests'):\n      # This graph has subgraphs (traces).\n      return RunnableConfig\n    else:\n      # This graph has no subgraphs, it's a leaf.\n      return RunnableLeafTraceConfig\n  elif suite.get('tests'):\n    # This is neither a leaf nor a runnable.\n    return GraphConfig\n  else:  # pragma: no cover\n    raise Exception('Invalid suite configuration.' + str(suite)[:200])\n\n\ndef BuildGraphConfigs(suite, parent, arch):\n  \"\"\"Builds a tree structure of graph objects that corresponds to the suite\n  configuration.\n\n  - GraphConfig:\n    - Can have arbitrary children\n    - can be used to store properties used by its children\n\n  - VariantConfig\n    - Has variants of the same (any) type as children\n\n  For all other configs see the override AppendChild methods.\n\n  Example 1:\n  - GraphConfig\n    - RunnableLeafTraceConfig (no children)","sourceCodeStart":638,"sourceCodeEnd":674,"githubUrl":"https://github.com/nodejs/node/blob/1b2de5e052fc0fb95fd7fb6846dcec4ade598e9e/deps/v8/tools/run_perf.py#L638-L674","documentation":"Thrown by MakeGraphConfig in run_perf.py when a suite dict contains neither a 'main' key nor a 'tests' key, so the builder cannot decide whether the node is runnable, a graph, or a leaf. It is marked '# pragma: no cover' because the surrounding branches are expected to catch all valid combinations, so hitting it means the suite dict is structurally malformed.","triggerScenarios":"A suite configuration entry missing both 'main' and 'tests' keys reaches MakeGraphConfig. This is only reachable if an upstream guard (which normally rejects keyless suites) is bypassed or if a suite file is hand-edited to drop both fields.","commonSituations":"Hand-editing a V8 perf benchmark JSON and deleting the 'tests' array from a node that had no 'main'; or a YAML->JSON conversion / templating step that stripped empty keys.","solutions":["Open the suite JSON named on the command line and find the node with neither 'main' nor 'tests'; add the missing key.","If the node is meant to be a pure grouping node, give it a 'tests' array; if it should run a script, add 'main'.","Re-run with the same JSON and confirm MakeGraphConfig now returns a concrete class (RunnableConfig / GraphConfig / LeafTraceConfig)."],"exampleFix":"// before\n{ \"name\":\"group\" }\n// after\n{ \"name\":\"group\", \"tests\": [] }","handlingStrategy":"validation","validationCode":"def validate_suite(suite):\n    if 'main' not in suite and 'tests' not in suite:\n        raise ValueError(f\"Suite {suite.get('name','?')} has neither 'main' nor 'tests'; add one before running run_perf.\")\n    return True","typeGuard":"def is_valid_suite_dict(suite: dict) -> bool:\n    return isinstance(suite, dict) and ('main' in suite or 'tests' in suite)","tryCatchPattern":"null","preventionTips":["Lint perf suite JSON files in CI for the presence of 'main' or 'tests' on every node.","Avoid hand-editing benchmark JSON without re-running a dry validation pass."],"tags":["v8","perf-test","configuration","unreachable"],"backgroundTag":null,"analyzedSha":"1b2de5e052fc0fb95fd7fb6846dcec4ade598e9e","analyzedAt":"2026-08-13T00:53:24.642Z","schemaVersion":2},"datasetVersion":"2026-08-13T04:17:16.726Z"}