pinpoint-apm/pinpoint · error · IllegalArgumentException

agentStartTimeIndex not found

Error message

agentStartTimeIndex not found:${transactionId}

What it means

TransactionIdUtils.parseTransactionId splits a transactionId string (format: agentId^agentStartTime^transactionSequence) on delimiters. When no second delimiter exists after the agentId, nextIndex returns -1 and this IllegalArgumentException is thrown, meaning the transactionId string is malformed and cannot be decomposed into its components.

Solutions

  1. Verify the transactionId is produced by TransactionIdUtils.formatString / TransactionId objects, not hand-concatenated
  2. Check that the string contains the expected delimiters between agentId, agentStartTime, and transactionSequence before calling parseTransactionId
  3. Validate the id came from a pinpoint span/trace source and was not truncated by storage or logging
  4. Wrap parseTransactionId in try-catch and treat the input as a malformed/foreign id

Example fix

// before
TransactionId id = TransactionIdUtils.parseTransactionId(agentIdLine);
// after
if (agentIdLine != null && agentIdLine.indexOf(TransactionIdUtils.AGENT_ID_DELIMITER) > -1) {
    TransactionId id = TransactionIdUtils.parseTransactionId(agentIdLine);
} else {
    throw new IllegalArgumentException("malformed transactionId: " + agentIdLine);
}
Defensive patterns

Strategy: validation

Validate before calling

boolean isParseableTransactionId(String s) {
    if (s == null) return false;
    int first = s.indexOf(TransactionIdUtils.AGENT_ID_DELIMITER);
    return first > 0 && s.indexOf(TransactionIdUtils.AGENT_ID_DELIMITER, first + 1) != -1;
}

Type guard

boolean isParseableTransactionId(String s) {
    if (s == null) return false;
    int first = s.indexOf(TransactionIdUtils.AGENT_ID_DELIMITER);
    return first > 0 && s.indexOf(TransactionIdUtils.AGENT_ID_DELIMITER, first + 1) != -1;
}

Try / catch

try {
    TransactionId id = TransactionIdUtils.parseTransactionId(txId);
} catch (IllegalArgumentException e) {
    log.warn("malformed transactionId: {}", txId, e);
    // treat as foreign/legacy id, skip or fall back
}

Prevention

When it happens

Trigger: Calling TransactionIdUtils.parseTransactionId with a string that has an agentId but no delimiter after it, e.g. 'myAgentId' or 'myAgentId12345' (missing the separator between agentId and agentStartTime).

Common situations: Passing a raw string value (agentId alone, or a traceId copied partially) instead of a full transactionId; hand-building transactionId strings with the wrong delimiter; older/newer pinpoint versions or custom storage rows where the id was truncated or not encoded with TransactionIdUtils.formatString.

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 pinpoint-apm/pinpoint@744c3d3075 (2026-09-07). Data as JSON: /api/errors/5d223429dffc2dbd. Report an issue: GitHub.

Appendix: source

Thrown at commons-profiler/src/main/java/com/navercorp/pinpoint/common/profiler/util/TransactionIdUtils.java:98

        BytesUtils.writeVar64(transactionSequence, buffer, offset);
        return buffer;
    }

    public static TransactionId parseTransactionId(final String transactionId) {
        Objects.requireNonNull(transactionId, "transactionId");

        final int agentIdIndex = nextIndex(transactionId, 0);
        if (agentIdIndex == -1) {
            throw new IllegalArgumentException("agentIndex not found:" + transactionId);
        }
        if (!IdValidateUtils.checkId(transactionId, 0, agentIdIndex)) {
            throw new IllegalArgumentException("invalid transactionId:" + transactionId);
        }
        final String agentId = transactionId.substring(0, agentIdIndex);

        final int agentStartTimeIndex = nextIndex(transactionId, agentIdIndex + 1);
        if (agentStartTimeIndex == -1) {
            throw new IllegalArgumentException("agentStartTimeIndex not found:" + transactionId);
        }
        final long agentStartTime = parseLong(transactionId, agentIdIndex + 1, agentStartTimeIndex);

        int transactionSequenceIndex = nextIndex(transactionId, agentStartTimeIndex + 1);
        if (transactionSequenceIndex == -1) {
            // next index may not exist since default value does not have a delimiter after transactionSequence.
            // may need fixing when id spec changes
            transactionSequenceIndex = transactionId.length();
        }
        final long transactionSequence = parseLong(transactionId, agentStartTimeIndex + 1, transactionSequenceIndex);
        return TransactionId.of(agentId, agentStartTime, transactionSequence);
    }

    private static int nextIndex(String transactionId, int fromIndex) {
        return transactionId.indexOf(TRANSACTION_ID_DELIMITER_CHAR, fromIndex);
    }

    private static long parseLong(String transactionId, int beginIndex, int endIndex) {

View on GitHub (pinned to 744c3d3075)