apache/beam · error

Unknown PaneInfo encoding 0x" + encoding.toString(16)

Error message

Unknown PaneInfo encoding 0x" + encoding.toString(16)

What it means

During to_runner_api_transform, coder protos from the expanded components are merged into the pipeline context. If an expanded coder id collides with an existing coder id in the context but the two protos are not equivalent, RuntimeError is raised to prevent silently overwriting a different coder under the same id. Equivalent coders are tolerated; distinct coders are not.

Source

Thrown at sdks/typescript/src/apache_beam/coders/required_coders.ts:610

          isLast: isLast,
          index: onlyIndex,
          onTimeIndex: timing === Timing.EARLY ? -1 : onlyIndex,
          timing: timing,
        };

      case PaneInfoEncoding.TWO_INDICES:
        // Both pane index and non-speculative index included
        const paneIndex = reader.int32();
        const nonSpeculativeIndex = reader.int32();
        return {
          isFirst: isFirst,
          isLast: isLast,
          index: paneIndex,
          onTimeIndex: nonSpeculativeIndex,
          timing: timing,
        };
      default:
        throw new Error("Unknown PaneInfo encoding 0x" + encoding.toString(16));
    }
  }

  encode(value: PaneInfo, writer: Writer, context: Context) {
    // low 4 bits are used regardless of encoding
    const low4 =
      (value.isFirst ? 0b000000001 : 0) |
      (value.isLast ? 0b00000010 : 0) |
      (PaneInfoCoder.encodeTiming(value.timing) << 2);

    const encodingNibble: PaneInfoEncoding =
      PaneInfoCoder.chooseEncoding(value);
    writeRawByte(low4 | (encodingNibble << 4), writer);

    switch (encodingNibble) {
      case PaneInfoEncoding.NO_INDEX:
        // the header byte contains all the info
        return;

View on GitHub (pinned to 12126d8942)

Solutions

  1. Upgrade apache-beam so coder id namespaces/proto definitions are consistent between SDK and expansion service.
  2. Ensure the expansion service jar version matches the SDK version.
  3. If authoring a custom external transform, namespace your coder ids (prefix with the external namespace) to avoid collisions.

Example fix

// before
# expansion returns coder id 'coder1' differing from pipeline's 'coder1'
// after
# use a matching SDK/expansion-service version, or id like 'external_1-coder1'
Defensive patterns

Strategy: try-catch

Validate before calling

# before expanding, ensure no conflicting coder ids:
for cid in expanded_components.coders:
    if cid in context.coders: check_equivalent(context.coders._id_to_proto[cid], proto)

Type guard

def coder_ids_safe(components, context, ns: str) -> bool:
    return all(cid.startswith(ns) or cid not in context.coders for cid in components.coders)

Try / catch

try:
    result = p | external_transform
except RuntimeError as e:
    if 'Re-used coder id' in str(e):
        logger.error('Coder id collision across expansions: %s', e)
    raise

Prevention

When it happens

Trigger: An ExternalTransform's expansion returns components containing a coder id (not namespaced with the external namespace) that already exists in the pipeline's coder registry but with a different proto definition.

Common situations: Multiple external expansions of differently configured transforms producing colliding ids; Beam version skew where coder proto encoding changed; reusing the same coder id across separately expanded transforms.

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


AI-assisted analysis of apache/beam@12126d8942 (2026-09-13). Data as JSON: /api/errors/73b365f412afe17c. Report an issue: GitHub.