apache/beam · error · IllegalArgumentException

SolaceIO.Write: Unknown destination type

Error message

SolaceIO.Write: Unknown destination type: ${destination.getType()}

What it means

SolaceIO.Write's convertToJcsmpDestination only maps TOPIC and QUEUE destination types; any other Solace.DestinationType throws this IllegalArgumentException. It is a defensive check that every destination the writer emits is one JCSMP can represent.

Solutions

  1. Return Solace.DestinationType.TOPIC or QUEUE from your Destination implementation.
  2. In your custom mapping, build a topic-only Destination: use Solace.DestinationType.TOPIC with the topic name.
  3. Check the version of the solace mapping classes matches the Beam SolaceIO version you use.
  4. If a temporary destination is needed, create it via the JCSMP session directly instead of the generic Destination mapping.

Example fix

// before
public Solace.DestinationType getType() { return Solace.DestinationType.TEMPORARY_QUEUE; }
// after
public Solace.DestinationType getType() { return Solace.DestinationType.QUEUE; }
Defensive patterns

Strategy: type-guard

Validate before calling

// Validate destination types before submitting the write
// if (dest.getType() != Solace.DestinationType.TOPIC && dest.getType() != Solace.DestinationType.QUEUE)
//   throw new IllegalArgumentException("Unsupported destination type: " + dest.getType());

Type guard

boolean isWritableDestination(Solace.Destination d) {
  return d != null && (d.getType() == Solace.DestinationType.TOPIC || d.getType() == Solace.DestinationType.QUEUE);
}

Try / catch

try { pipeline.run(); }
catch (IllegalArgumentException e) {
  if (e.getMessage().startsWith("SolaceIO.Write: Unknown destination type")) fixDestinationMapping();
  else throw e;
}

Prevention

When it happens

Trigger: A custom Solace.Destination whose getType() is not TOPIC or QUEUE is supplied to SolaceIO.Write (custom destination mappings / subclassed Destination), reaching convertToJcsmpDestination during message serialization.

Common situations: Implementing a custom Destination with an invented type (e.g. TEMPORARY_TOPIC) unsupported by Beam's Solace writer; mapping library version mismatch returning an unexpected enum value.

Understand the failure class

Background: Invalid enum value errors: "Unknown type", "Invalid scope", "must be one of" — when a string is not on the library's allowed list — this error's family across 23 libraries.

Related errors


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

Appendix: source

Thrown at sdks/java/io/solace/src/main/java/org/apache/beam/sdk/io/solace/SolaceIO.java:457

  /** Get a {@link Queue} object from the queue name. */
  static Queue queueFromName(String queueName) {
    return JCSMPFactory.onlyInstance().createQueue(queueName);
  }

  /**
   * Convert to a JCSMP destination from a schema-enabled {@link
   * org.apache.beam.sdk.io.solace.data.Solace.Destination}.
   *
   * <p>This method returns a {@link Destination}, which may be either a {@link Topic} or a {@link
   * Queue}
   */
  public static Destination convertToJcsmpDestination(Solace.Destination destination) {
    if (destination.getType().equals(Solace.DestinationType.TOPIC)) {
      return topicFromName(checkNotNull(destination.getName()));
    } else if (destination.getType().equals(Solace.DestinationType.QUEUE)) {
      return queueFromName(checkNotNull(destination.getName()));
    } else {
      throw new IllegalArgumentException(
          "SolaceIO.Write: Unknown destination type: " + destination.getType());
    }
  }

  /**
   * Create a {@link Read} transform, to read from Solace. The ingested records will be mapped to
   * the {@link Solace.Record} objects.
   */
  public static Read<Solace.Record> read() {
    return new Read<Solace.Record>(
        Read.Configuration.<Solace.Record>builder()
            .setTypeDescriptor(TypeDescriptor.of(Solace.Record.class))
            .setParseFn(SolaceRecordMapper::toRecord)
            .setTimestampFn(SENDER_TIMESTAMP_FUNCTION)
            .setDeduplicateRecords(DEFAULT_DEDUPLICATE_RECORDS)
            .setWatermarkIdleDurationThreshold(DEFAULT_WATERMARK_IDLE_DURATION_THRESHOLD)
            .setAckDeadline(DEFAULT_ACK_DEADLINE)
            .setNackOnTimeout(DEFAULT_NACK_ON_TIMEOUT));

View on GitHub (pinned to 12126d8942)