Code review comment: Thinking about this a bit more, perhaps always having an empty PCollection here would be good. Then people can unconditionally do things like add up all the errors or check for them etc.

Code under review:
public PCollectionRowTuple expand(PCollectionRowTuple input) {

          
          
          
          
          String queryString = config.getString("query");
          if (queryString == null) {
            throw new IllegalArgumentException("Configuration must provide a query string.");
          }
          SqlTransform transform = SqlTransform.query(queryString);

          
          EnumerationType.Value dialect =
              config.getLogicalTypeValue("dialect", EnumerationType.Value.class);
          if (dialect != null) {
            Class<? extends QueryPlanner> queryPlannerClass =
                QUERY_PLANNERS.get(QUERY_ENUMERATION.toString(dialect));
            if (queryPlannerClass != null) {
              transform = transform.withQueryPlannerClass(queryPlannerClass);
            }
          }

          
          String ddl = config.getString("ddl");
          if (ddl != null) {
            transform = transform.withDdlString(ddl);
          }

          
          Boolean autoload = config.getBoolean("autoload");
          if (autoload != null && autoload) {
            transform = transform.withAutoLoading(true);
          } else {
            transform = transform.withAutoLoading(false);

            
            Map<String, TableProvider> tableProviders = new HashMap<>();
            ServiceLoader.load(TableProvider.class)
                .forEach(
                    (provider) -> {
                      tableProviders.put(provider.getTableType(), provider);
                    });
            Collection<?> tableproviderList = config.getArray("tableproviders");
            if (tableproviderList != null) {
              for (Object nameObj : tableproviderList) {
                if (nameObj != null) { 
                  TableProvider p = tableProviders.get(nameObj);
                  if (p
                      != null) { 
                    
                    transform = transform.withTableProvider(p.getTableType(), p);
                  }
                }
              }
            }
          }

          
          

          
          ErrorCapture errors = new ErrorCapture();
          PCollection<Row> output = input.apply(transform.withErrorsTransformer(errors));

          
          
          
          

          List<PCollection<Row>> errorList = errors.getInputs();
          if (errorList.size() == 0) {
            return PCollectionRowTuple.of("output", output);
          } else if (errorList.size() == 1) {
            return PCollectionRowTuple.of("output", output, "errors", errorList.get(0));
          } else {
            throw new UnsupportedOperationException(
                "SqlTransform currently only supports a single dead letter queue collection");
          }
        }

Line commented on: if (errorList.size() == 0) {

Revised code:
public PCollectionRowTuple expand(PCollectionRowTuple input) {

          
          
          
          
          String queryString = config.getString("query");
          if (queryString == null) {
            throw new IllegalArgumentException("Configuration must provide a query string.");
          }
          SqlTransform transform = SqlTransform.query(queryString);

          
          EnumerationType.Value dialect =
              config.getLogicalTypeValue("dialect", EnumerationType.Value.class);
          if (dialect != null) {
            Class<? extends QueryPlanner> queryPlannerClass =
                QUERY_PLANNERS.get(QUERY_ENUMERATION.toString(dialect));
            if (queryPlannerClass != null) {
              transform = transform.withQueryPlannerClass(queryPlannerClass);
            }
          }

          
          String ddl = config.getString("ddl");
          if (ddl != null) {
            transform = transform.withDdlString(ddl);
          }

          
          Boolean autoload = config.getBoolean("autoload");
          if (autoload != null && autoload) {
            transform = transform.withAutoLoading(true);
          } else {
            transform = transform.withAutoLoading(false);

            
            Map<String, TableProvider> tableProviders = new HashMap<>();
            ServiceLoader.load(TableProvider.class)
                .forEach(
                    (provider) -> {
                      tableProviders.put(provider.getTableType(), provider);
                    });
            Collection<?> tableproviderList = config.getArray("tableproviders");
            if (tableproviderList != null) {
              for (Object nameObj : tableproviderList) {
                if (nameObj != null) { 
                  TableProvider p = tableProviders.get(nameObj);
                  if (p
                      != null) { 
                    
                    transform = transform.withTableProvider(p.getTableType(), p);
                  }
                }
              }
            }
          }

          
          

          
          ErrorCapture errors = new ErrorCapture();
          PCollection<Row> output = input.apply(transform.withErrorsTransformer(errors));

          
          
          
          

          List<PCollection<Row>> errorList = errors.getInputs();
          if (errorList.size() == 0) {
            PCollection<Row> emptyErrors =
                input
                    .getPipeline()
                    .apply(Create.empty(BeamSqlRelUtils.getErrorRowSchema(Schema.of())));
            return PCollectionRowTuple.of("output", output, "errors", emptyErrors);
          } else if (errorList.size() == 1) {
            return PCollectionRowTuple.of("output", output, "errors", errorList.get(0));
          } else {
            throw new UnsupportedOperationException(
                "SqlTransform currently only supports a single dead letter queue collection");
          }
        }