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, soView on GitHub (pinned to 102af09b4a)
Solutions
- 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
- Verify cluster-wide that no peer concurrently registered the same metric names (rollouts racing)
- 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
- 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
- Reserve metric prefixes per team/bundle to prevent cross-file name collisions
- List installed meters before applying a renamed or duplicated bundle
- Treat the partial set in the exception as authoritative for cleanup — it is deliberately the landed subset, not the enumeration
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
- {causeMessage} — {rootCauseMessage}
- phase-2 register failed for {}
- LAL register failed for rule '{ruleName}' in {sourceName}
- MAL compile failed for {sourceName}
- teardown_deferred
AI-assisted analysis of apache/skywalking@102af09b4a (2026-08-14).
Data as JSON: /api/errors/c2bec266ef72113c.
Report an issue: GitHub.