apache/skywalking · error · ApplyException

MAL register failed for {sourceName} (partial)

Error message

MAL register failed for {sourceName} (partial)

What it means

ApplyException thrown by MalFileApplier.apply when MetricConvert construction throws PartialRegistrationException — phase-2 MeterSystem registration got partway through the file's metrics before failing. Crucially, the exception carries ONLY the metric subset that actually landed (pre.getRegisteredBeforeFailure()), never the fully enumerated set: on FILTER_ONLY edits every metric name also exists in the old bundle, so over-broad rollback would delete metrics the still-serving old rule owns. Layer-registry claims are rolled back immediately before throwing.

Source

Thrown at oap-server/server-admin/runtime-rule/src/main/java/org/apache/skywalking/oap/server/receiver/runtimerule/apply/MalFileApplier.java:163

            ? sourceName.substring(firstSlash + 1)
            : sourceName;
        final RuleClassLoader ruleLoader = DSLClassLoaderManager.INSTANCE.newBuilder(
            catalog, ruleName, kind, contentHash);
        final ClassPool pool = new ClassPool(ClassPool.getDefault());
        pool.appendClassPath(new LoaderClassPath(ruleLoader));

        final MetricConvert convert;
        try {
            convert = new MetricConvert(rule, meterSystem, pool, ruleLoader, storageOpt);
        } catch (final MetricConvert.PartialRegistrationException pre) {
            // Phase-2 register threw partway. Carry ONLY the subset that actually landed in
            // MeterSystem — the caller uses this set for rollback. Passing the full enumerated
            // set here would remove metrics the old bundle still owns (disastrous on
            // FILTER_ONLY edits, where by definition every metric name is also in the old
            // bundle). The layer-registry changes are reverted now so a failed MeterSystem
            // register does not leak a half-applied layer state.
            layerRegistry.rollback(appliedClaims);
            throw new ApplyException(
                "MAL register failed for " + sourceName + " (partial)",
                pre.getCause() == null ? pre : pre.getCause(),
                pre.getRegisteredBeforeFailure());
        } catch (final Throwable t) {
            // Phase-1 compile failure or other pre-register throw. Nothing was registered with
            // MeterSystem, so rollback set is empty — passing a non-empty set would cause the
            // caller to unregister metrics the old bundle owns and this apply never touched.
            layerRegistry.rollback(appliedClaims);
            throw new ApplyException("MAL compile failed for " + sourceName, t, Collections.emptySet());
        }
        // All DDL for this file's metrics is now fired. If the opt deferred its schema fence
        // (batched apply via withSchemaChangeDeferredFence), run the single barrier here so the
        // whole file waits ONCE instead of one fence per metric/downsampling. A fence timeout is
        // a non-fatal WARN inside the closure; only a barrier transport error throws, which
        // aborts this apply exactly as an inline per-resource fence would have.
        //
        // EXCEPTION: when fenceRunByCaller is set (the runtime-rule REST apply), the orchestrator
        // runs the fence itself AFTER the durable commit + peer resume, on a background thread, so

View on GitHub (pinned to 102af09b4a)

Solutions

  1. Check the cause for the failing metric name; if it collides, rename the metric in the new file or remove the old bundle that owns it
  2. Verify cluster-wide that no peer concurrently registered the same metric names (rollouts racing)
  3. Retry the apply after storage is healthy if the cause was a storage DDL/stream failure — the applier already rolled back layer claims, and the returned partial set lets the orchestrator unregister only what landed
  4. Audit for stale bundles: list registered meters and remove orphaned files before re-apply
Defensive patterns

Strategy: try-catch

Validate before calling

// Pre-flight: ensure no metric name in the new file is already registered elsewhere
Set<String> existing = meterSystemHasTheseNames(newFileMetricNames(prefix, rules));
if (!Collections.disjoint(existing, incomingNames)) reject("metric name collision: " + overlap);

Try / catch

catch (MalFileApplier.ApplyException e) when 'MAL register failed ... (partial)': unregister EXACTLY e.getPartiallyRegistered() (the subset that landed), then resolve the colliding/failed metric from the cause and re-apply. Never roll back more than the partial set — the old bundle still owns the rest.

Prevention

When it happens

Trigger: Applying a MAL file where one metric registers into MeterSystem but a later one fails — duplicate metric name already in MeterSystem, a metric definition rejected by storage DDL, or an expression compiling to an invalid metric type mid-registration.

Common situations: A hot-updated MAL file introduces a metric name that another MAL bundle (often an otel-rules file) already registered; Transient storage unavailability while opening streams during registration; Metric name collisions after renaming a rule but keeping the old file installed in parallel

Related errors


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