apache/beam · error
Unknown timing constant: " + timing
Error message
Unknown timing constant: " + timing
What it means
ExternalTransform.to_runner_api_transform raises RuntimeError when translating an expanded external transform to its runner API form and more than one input tag was renamed (not present in the expanded transform's inputs). With non-preserved tags there is no way to map original tags to expanded tags unambiguously once two renames are seen, so the translation aborts. This is an internal consistency check during pipeline serialization.
Source
Thrown at sdks/typescript/src/apache_beam/coders/required_coders.ts:544
"Timing number 0b" +
timingNumber.toString(2) +
" has more than two bits of info",
);
}
}
private static encodeTiming(timing: Timing): number {
switch (timing) {
case Timing.EARLY:
return 0b00;
case Timing.ON_TIME:
return 0b01;
case Timing.LATE:
return 0b10;
case Timing.UNKNOWN:
return 0b11;
default:
throw new Error("Unknown timing constant: " + timing);
}
}
private static chooseEncoding(value: PaneInfo): number {
if (
(value.index === 0 && value.onTimeIndex === 0) ||
value.timing === Timing.UNKNOWN
) {
return PaneInfoEncoding.NO_INDEX;
} else if (
value.index === value.onTimeIndex ||
value.timing === Timing.EARLY
) {
return PaneInfoEncoding.ONE_INDEX;
} else {
return PaneInfoEncoding.TWO_INDICES;
}
}View on GitHub (pinned to 12126d8942)
Solutions
- Ensure input tags match the expanded transform's tags; do not rename inputs of an external transform after expansion.
- Upgrade/downgrade apache-beam so the Python SDK and the expansion service jar agree on tag naming.
- Report/inspect the two key sets in the message to identify which transform's tags drifted.
Example fix
// before
p | 'label' >> ExternalTransform(...).with_inputs({'wrong_tag': pcoll})
// after
p | 'label' >> ExternalTransform(...).with_inputs({'expected_tag': pcoll}) # match expanded tags Defensive patterns
Strategy: try-catch
Validate before calling
assert set(t._inputs).issubset(set(t._expanded_transform.inputs)) or len(t._inputs) == 1
Type guard
def tags_preserved(local_inputs: dict, expanded_inputs: dict) -> bool:
return set(local_inputs) == set(expanded_inputs) Try / catch
try:
run_pipeline(pipeline)
except RuntimeError as e:
if 'non-preserved tags' in str(e):
logger.error('External transform input tags drifted; align SDK and jar versions: %s', e)
raise Prevention
- Keep apache-beam SDK and expansion service jar versions aligned
- Do not rename input tags on external transforms after expansion
- Use with_input/with_outputs with the tags the expansion service defines
When it happens
Trigger: Applying an ExternalTransform whose expanded counterpart has a single input while the applied transform has multiple local input tags not matching the expanded tags, causing repeated single-input remapping; typically with multi-input external transforms whose tags were not preserved across expansion.
Common situations: Cross-language transforms where the Java expansion renamed/normalized input tags; manually constructed ExternalTransform objects with arbitrary tags; Beam version mismatch causing tag schema changes between SDK and expansion service.
Understand the failure class
Background: "This is a bug, please report it": internal invariant violations, unreachable panics, and SNH errors explained — this error's family across 47 libraries.
Related errors
- Unknown PaneInfo encoding 0x" + encoding.toString(16)
- Could not find coder for URN " + urn
- to_runner_api_parameter not implemented for type
- Only one of context or default_environment may be specified.
- No producer for %s
AI-assisted analysis of apache/beam@12126d8942 (2026-09-13).
Data as JSON: /api/errors/871bcf5d978cc0f0.
Report an issue: GitHub.