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
- 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
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
- 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
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
- Invalid stageNumber [%s]
- No such stage[%s]
- Invalid segment granularity [%s]
- Cannot deserialize type[%s] to an RoaringBitmap64Counter:
- Unable to parse line.
AI-assisted analysis of apache/druid@9b90983fd2 (2026-09-07).
Data as JSON: /api/errors/0e01e2bbc19aeb35.
Report an issue: GitHub.