apache/skywalking · error · UnexpectedException

Can't split service id into 2 parts

Error message

Can't split service id into 2 parts, {}

What it means

UnexpectedException thrown by IDManager.ServiceID.analysisId(String) when a service ID string cannot be split into exactly 2 parts by Const.SERVICE_ID_PARSER_SPLIT. Service IDs are built by buildId(name, isNormal) as encode(name) + '.' + booleanValue(0/1); analysisId is the inverse and treats any other shape as data corruption. The offending id is included in the message.

Solutions

  1. Always build ids with IDManager.ServiceID.buildId(name, isNormal) and only pass those to analysisId
  2. If hand-constructing, match the exact format: URL-encoded name + Const.SERVICE_ID_CONNECTOR + '0'|'1'
  3. Log the failing id (it is in the message) and trace which writer produced it — usually a non-standard producer
  4. On version-skew migrations, reindex/rewrite stored ids or read them with the old format

Example fix

// before
ServiceIDDefinition def = IDManager.ServiceID.analysisId(serviceName); // raw name -> throws

// after
String id = IDManager.ServiceID.buildId(serviceName, true);
ServiceIDDefinition def = IDManager.ServiceID.analysisId(id);
Defensive patterns

Strategy: type-guard

Validate before calling

String PATTERN = "^[^.]+\\.[01]$"; // encoded-name '.' 0|1
if (id == null || !id.matches(PATTERN)) {
    throw new IllegalArgumentException("Not a service id produced by IDManager.ServiceID.buildId: " + id);
}

Type guard

boolean isServiceId(String id) {
    return id != null && id.matches("^[^.]+\\.[01]$");
}

Try / catch

try {
    ServiceIDDefinition def = IDManager.ServiceID.analysisId(id);
} catch (UnexpectedException e) {
    LOGGER.warn("Skipping malformed service id: {}", id, e);
}

Prevention

When it happens

Trigger: Calling ServiceID.analysisId on a string that is not a buildId product: a raw service name without the connector, an id built with a different connector constant, an id with extra '.' segments because the encoded name leaks an unencoded '.', or null/empty passed in.

Common situations: Custom storage/receiver code re-implementing id assembly instead of calling buildId; version skew where a producer encodes differently than the consumer decodes; unit tests feeding hand-crafted ids; data written by an old OAP being read by new code after encoding changes.

Related errors


AI-assisted analysis of apache/skywalking@102af09b4a (2026-08-14). Data as JSON: /api/errors/2c1b3c33da11e86c. Report an issue: GitHub.

Appendix: source

Thrown at oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/analysis/IDManager.java:59

        /**
         * @param name     service name
         * @param isNormal `true` represents this service is detected by an agent. `false` represents this service is
         *                 conjectured by telemetry data collected from agents on/in the `normal` service.
         */
        public static String buildId(String name, boolean isNormal) {
            if (StringUtil.isBlank(name)) {
                name = Const.BLANK_ENTITY_NAME;
            }
            return encode(name) + Const.SERVICE_ID_CONNECTOR + BooleanUtils.booleanToValue(isNormal);
        }

        /**
         * @return service ID object decoded from {@link #buildId(String, boolean)} result
         */
        public static ServiceIDDefinition analysisId(String id) {
            final String[] strings = id.split(Const.SERVICE_ID_PARSER_SPLIT);
            if (strings.length != 2) {
                throw new UnexpectedException("Can't split service id into 2 parts, " + id);
            }
            return new ServiceID.ServiceIDDefinition(
                decode(strings[0]),
                BooleanUtils.valueToBoolean(Integer.parseInt(strings[1]))
            );
        }

        /**
         * @return encoded service relation id
         */
        public static String buildRelationId(ServiceRelationDefine define) {
            return define.sourceId + Const.RELATION_ID_CONNECTOR + define.destId;
        }

        /**
         * @return encoded service hierarchy relation id
         */
        public static String buildServiceHierarchyRelationId(ServiceHierarchyRelationDefine define) {

View on GitHub (pinned to 102af09b4a)