{"record":{"id":"0e01e2bbc19aeb35","repo":"apache/druid","slug":"not-a-valid-stage-id-s","errorCode":null,"errorMessage":"Not a valid stage id: [%s]","messagePattern":"Not a valid stage id: \\[(.+?)\\]","errorType":"validation","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"multi-stage-query/src/main/java/org/apache/druid/msq/kernel/StageId.java","lineNumber":70,"sourceCode":"\n    this.queryId = IdUtils.validateId(\"queryId\", queryId);\n    this.stageNumber = stageNumber;\n  }\n\n  @JsonCreator\n  public static StageId fromString(final String s)\n  {\n    final int lastUnderscore = s.lastIndexOf('_');\n\n    if (lastUnderscore > 0 && lastUnderscore < s.length() - 1) {\n      final Long stageNumber = GuavaUtils.tryParseLong(s.substring(lastUnderscore + 1));\n\n      if (stageNumber != null && stageNumber >= 0 && stageNumber <= Integer.MAX_VALUE) {\n        return new StageId(s.substring(0, lastUnderscore), stageNumber.intValue());\n      }\n    }\n\n    throw new IAE(\"Not a valid stage id: [%s]\", s);\n  }\n\n  public String getQueryId()\n  {\n    return queryId;\n  }\n\n  public int getStageNumber()\n  {\n    return stageNumber;\n  }\n\n  @Override\n  public int compareTo(StageId that)\n  {\n    return COMPARATOR.compare(this, that);\n  }\n","sourceCodeStart":52,"sourceCodeEnd":88,"githubUrl":"https://github.com/apache/druid/blob/9b90983fd291f26935af934383ce360473179e4d/multi-stage-query/src/main/java/org/apache/druid/msq/kernel/StageId.java#L52-L88","documentation":"StageId.fromString parses strings of the form '<queryId>_<stageNumber>' and throws IAE when the string does not end with an underscore followed by a non-negative integer. Any malformed identifier — missing underscore suffix, non-numeric stage part, or negative stage — fails this parse.","triggerScenarios":"Calling StageId.fromString with strings like 'query-abc' (no _stage suffix), 'query-abc_xyz' (stage part not numeric), or 'query-abc_-1' (negative stage).","commonSituations":"Users paste a truncated or manually edited stage identifier from logs or the UI; tooling concatenates queryId and stage with the wrong separator; a stage name was copied including extra trailing characters.","solutions":["Check the string ends with an underscore followed by a non-negative integer, e.g. 'q_0'","Use StageId.toString() (or queryId + \"_\" + stageNumber) to build the id rather than hand-formatting it","Verify the source of the identifier (log line, API response) and re-fetch the full untruncated value"],"exampleFix":"// before\nStageId id = StageId.fromString(queryId + stageNumber);\n// after\nStageId id = StageId.fromString(queryId + \"_\" + stageNumber);","handlingStrategy":"validation","validationCode":"java.util.regex.Pattern STAGE_ID = Pattern.compile(\"^.+_\\\\d+$\");\nif (s == null || !STAGE_ID.matcher(s).matches()) throw new IllegalArgumentException(\"Malformed stage id: \" + s);\nStageId id = StageId.fromString(s);","typeGuard":"boolean looksLikeStageId(String s) { return s != null && s.matches(\"^.+_\\\\d+$\"); }","tryCatchPattern":"try { StageId id = StageId.fromString(s); } catch (IllegalArgumentException e) { log.warn(\"Bad stage id {}: {}\", s, e.getMessage()); return; }","preventionTips":["Always build ids with StageId.toString() instead of string concatenation","Copy full identifiers, never truncated log output","Add a regex pre-check before parsing user-supplied ids"],"tags":["java","parsing","msq"],"backgroundTag":"invalid-argument-format","analyzedSha":"9b90983fd291f26935af934383ce360473179e4d","analyzedAt":"2026-09-07T13:32:30.957Z","contentChangedAt":"2026-09-07T13:32:30.957Z","schemaVersion":2},"datasetVersion":"2026-09-14T11:17:12.474Z"}