alibaba/canal · error · CanalParseException

apply failed

Error message

apply failed

What it means

Thrown as CanalParseException by DatabaseTableMeta.applyHistoryOnMemory() when any Throwable occurs while replaying DDL history records from the TSDB into memory. Unlike error 436, this message has NO cause detail — it only says 'apply failed' with the exception attached.

Source

Thrown at parse/src/main/java/com/alibaba/otter/canal/parse/inbound/mysql/tsdb/DatabaseTableMeta.java:643

                // 如果是同一秒内,对比一下history的位点,如果比期望的位点要大,忽略之
                if (snapshotPosition.getTimestamp() > rollbackPosition.getTimestamp()) {
                    continue;
                } else if (rollbackPosition.getServerId().equals(snapshotPosition.getServerId())
                           && snapshotPosition.compareTo(rollbackPosition) > 0) {
                               continue;
                           }

                // 记录到内存
                if (!memoryTableMeta.apply(snapshotPosition, useSchema, sqlData, null)) {
                    return false;
                }

            }

            return metaHistoryDOList.size() > 0;
        } catch (Throwable e) {
            throw new CanalParseException("apply failed", e);
        }
    }

    private String structureSchema(String schema) {
        if (schema.startsWith("`") && schema.endsWith("`")) {
            return schema;
        }
        return "`" + schema + "`";
    }

    private String getFullName(String schema, String table) {
        StringBuilder builder = new StringBuilder();
        return builder.append(structureSchema(schema))
            .append('.')
            .append('`')
            .append(StringUtils.replace(table, "`", "``"))
            .append('`')
            .toString();

View on GitHub (pinned to 87be50e876)

Solutions

  1. Examine the attached cause exception (the 'e' parameter) for the real root cause — the message itself is uninformative.
  2. If NumberFormatException on binlogMasterId, inspect and clean the meta_history table for invalid masterId values.
  3. If memoryTableMeta.apply() returned false, check if the DDL text in the history record is valid and parseable.
  4. Clear corrupt history records from the TSDB and trigger a fresh full dump.
Defensive patterns

Strategy: fallback

Try / catch

try {
    tableMeta.rollback(position);
} catch (CanalParseException e) {
    if (e.getMessage().equals("apply failed")) {
        Throwable cause = e.getCause();
        // inspect cause: if NumberFormatException on masterId, clean history records
        // if DDL parse failure, remove corrupt history entry
    }
}

Prevention

When it happens

Trigger: memoryTableMeta.apply() returns false for a history DDL entry, OR an exception is thrown during the loop: metaHistoryDAO.findByTimestamp() fails, Long.valueOf(binlogMasterId) throws NumberFormatException for non-numeric master IDs, or EntryPosition.compareTo() fails.

Common situations: binlogMasterId in the TSDB history table is non-numeric or null (stored as string that fails Long.valueOf); corrupt DDL text in history table; TSDB connection lost during history query; version mismatch in the history record format.

Related errors


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