apache/druid · error · IllegalArgumentException

Not a valid stage id: [%s]

Error message

Not a valid stage id: [%s]

What it means

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.

Source

Thrown at multi-stage-query/src/main/java/org/apache/druid/msq/kernel/StageId.java:70

    this.queryId = IdUtils.validateId("queryId", queryId);
    this.stageNumber = stageNumber;
  }

  @JsonCreator
  public static StageId fromString(final String s)
  {
    final int lastUnderscore = s.lastIndexOf('_');

    if (lastUnderscore > 0 && lastUnderscore < s.length() - 1) {
      final Long stageNumber = GuavaUtils.tryParseLong(s.substring(lastUnderscore + 1));

      if (stageNumber != null && stageNumber >= 0 && stageNumber <= Integer.MAX_VALUE) {
        return new StageId(s.substring(0, lastUnderscore), stageNumber.intValue());
      }
    }

    throw new IAE("Not a valid stage id: [%s]", s);
  }

  public String getQueryId()
  {
    return queryId;
  }

  public int getStageNumber()
  {
    return stageNumber;
  }

  @Override
  public int compareTo(StageId that)
  {
    return COMPARATOR.compare(this, that);
  }

View on GitHub (pinned to 9b90983fd2)

Solutions

  1. Check the string ends with an underscore followed by a non-negative integer, e.g. 'q_0'
  2. Use StageId.toString() (or queryId + "_" + stageNumber) to build the id rather than hand-formatting it
  3. Verify the source of the identifier (log line, API response) and re-fetch the full untruncated value

Example fix

// before
StageId id = StageId.fromString(queryId + stageNumber);
// after
StageId id = StageId.fromString(queryId + "_" + stageNumber);
Defensive patterns

Strategy: validation

Validate before calling

java.util.regex.Pattern STAGE_ID = Pattern.compile("^.+_\\d+$");
if (s == null || !STAGE_ID.matcher(s).matches()) throw new IllegalArgumentException("Malformed stage id: " + s);
StageId id = StageId.fromString(s);

Type guard

boolean looksLikeStageId(String s) { return s != null && s.matches("^.+_\\d+$"); }

Try / catch

try { StageId id = StageId.fromString(s); } catch (IllegalArgumentException e) { log.warn("Bad stage id {}: {}", s, e.getMessage()); return; }

Prevention

When it happens

Trigger: Calling StageId.fromString with strings like 'query-abc' (no _stage suffix), 'query-abc_xyz' (stage part not numeric), or 'query-abc_-1' (negative stage).

Common situations: 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.

Understand the failure class

Background: "Invalid ... format", "must be in format X", "does not look like a ..." — invalid argument format errors across CLI tools and libraries — this error's family across 17 libraries.

Related errors


AI-assisted analysis of apache/druid@9b90983fd2 (2026-09-07). Data as JSON: /api/errors/0e01e2bbc19aeb35. Report an issue: GitHub.