alibaba/canal · error · RuntimeException

Target column: {targetColumnName} not matched

Error message

Target column: {targetColumnName} not matched

What it means

Thrown in PhoenixSyncService (insert/upsert column loop) when a target column name is not found in the cached target column type map (ctype). Unlike the condition builder, this path has a fallback: if mapAll and alter are enabled it attempts PhoenixEtlService.syncSchema to add the column; only if the column is still absent after that (and skipMissing is off) does it throw.

Source

Thrown at client-adapter/phoenix/src/main/java/com/alibaba/otter/canal/client/adapter/phoenix/service/PhoenixSyncService.java:412

            String targetColumnName = entry.getKey();
            String srcColumnName = entry.getValue();
            if (srcColumnName == null) {
                srcColumnName = Util.cleanColumn(targetColumnName);
            }

            Integer type = ctype.get(Util.cleanColumn(targetColumnName).toLowerCase());
            if (type == null) {
                if (dbMapping.isSkipMissing()) {
                    logger.warn("Target missing field: {}", targetColumnName);
                    mapLen -= 1;
                    continue;
                } else if (dbMapping.getMapAll() && dbMapping.isAlter() && PhoenixEtlService.syncSchema(batchExecutor.getConn(), config)) {
                    columnsTypeCache.remove(config.getDestination() + "." + dbMapping.getDatabase() + "." + dbMapping.getTable());
                    ctype = getTargetColumnType(batchExecutor.getConn(), config);
                    type = ctype.get(Util.cleanColumn(targetColumnName).toLowerCase());
                }
                if (type == null) {
                    throw new RuntimeException("Target column: " + targetColumnName + " not matched");
                }
            }
            insertSql.append(dbMapping.escape(targetColumnName)).append(",");
            Object value = data.get(srcColumnName);
            BatchExecutor.setValue(values, type, value);
        }

        int len = insertSql.length();
        insertSql.delete(len - 1, len).append(") VALUES (");
        for (int i = 0; i < mapLen; i++) {
            insertSql.append("?,");
        }
        len = insertSql.length();
        insertSql.delete(len - 1, len).append(")");

        Map<String, Object> old = dml.getOld();
        try {
            if (old != null && !old.isEmpty()) {

View on GitHub (pinned to 87be50e876)

Solutions

  1. Set 'skipMissing: true' in the dbMapping to drop unmapped columns instead of failing.
  2. Enable 'mapAll: true' and 'alter: true' so syncSchema adds missing columns automatically.
  3. Manually add the missing column to the target Phoenix table, or correct the targetColumns mapping / casing.

Example fix

# before
dbMapping:
  mapAll: true
  alter: false      # new columns cannot be added -> throws
# after
dbMapping:
  mapAll: true
  alter: true       # auto-adds missing columns
# or, to ignore missing columns
dbMapping:
  skipMissing: true
Defensive patterns

Strategy: validation

Validate before calling

// Before syncing, verify every targetColumns key exists in the target table.
Map<String,Integer> ctype = getTargetColumnType(conn, config);
Set<String> missing = config.getDbMapping().getTargetColumns().keySet().stream()
    .filter(c -> !ctype.containsKey(Util.cleanColumn(c).toLowerCase()))
    .collect(Collectors.toSet());
if (!missing.isEmpty() && !config.getDbMapping().isSkipMissing()) {
    throw new IllegalStateException(
        "Target columns missing and skipMissing=false: " + missing
        + " - set skipMissing:true or mapAll+alter:true");
}

Try / catch

try {
    syncService.sync(batchExecutor, items);
} catch (RuntimeException e) {
    if (e.getMessage().contains("Target column:") && e.getMessage().contains("not matched")) {
        logger.error("Schema drift: a target column is missing. "
            + "Enable mapAll+alter or skipMissing, or add the column.", e);
    }
    throw e;
}

Prevention

When it happens

Trigger: A DML references a column whose name is not in the target Phoenix table and not in ctype. With skipMissing=false and (mapAll=false OR alter=false OR syncSchema failed), the column remains unresolved.

Common situations: The source table gained a column not present in the target Phoenix table, and auto-alter is disabled or failed. A targetColumns mapping points at a target column that does not exist. Case mismatch when escapeUpper/escape is involved.

Related errors


AI-assisted analysis of alibaba/canal@87be50e876 (2026-08-14). Data as JSON: /api/errors/a722813188fc6dcb. Report an issue: GitHub.