{"record":{"id":"7aa832731be255ba","repo":"alibaba/canal","slug":"fetch-table-meta-failed-table","errorCode":null,"errorMessage":"fetch table meta failed. table: {}","messagePattern":"fetch table meta failed\\. table: (.+?)","errorType":"exception","errorClass":"CanalParseException","httpStatus":null,"severity":"error","filePath":"parse/src/main/java/com/alibaba/otter/canal/parse/inbound/mysql/dbsync/TableMetaCache.java","lineNumber":134,"sourceCode":"            result.add(meta);\n        }\n        return result;\n    }\n\n    private LoadingCache<String, TableMeta> createLocalCache() {\n        return CacheBuilder.newBuilder().build(new CacheLoader<String, TableMeta>() {\n\n            @Override\n            public TableMeta load(String name) throws Exception {\n                try {\n                    return getTableMetaByDB(name);\n                } catch (Throwable e) {\n                    // 尝试做一次retry操作\n                    try {\n                        connection.reconnect();\n                        return getTableMetaByDB(name);\n                    } catch (IOException e1) {\n                        throw new CanalParseException(\"fetch table meta failed. table: \" + name, e1);\n                    }\n                }\n            }\n        });\n    }\n\n    private TableMeta getTableMetaByDB(String fullname) throws IOException {\n        boolean showCreateTable = true;\n        ResultSetPacket packet = null;\n        synchronized (this) {\n            try {\n                packet = connection.query(\"show create table \" + fullname);\n            } catch (Exception ex) {\n                showCreateTable = false;\n                packet = connection.query(\"desc \" + fullname);\n            }\n        }\n        String[] names = StringUtils.split(fullname, \"`.`\");","sourceCodeStart":116,"sourceCodeEnd":152,"githubUrl":"https://github.com/alibaba/canal/blob/87be50e87686a3e8af08c368d0e1ffd1f59eb04a/parse/src/main/java/com/alibaba/otter/canal/parse/inbound/mysql/dbsync/TableMetaCache.java#L116-L152","documentation":"Thrown from the Guava LoadingCache loader in TableMetaCache.createLocalCache() when both the initial getTableMetaByDB() call and the retry (after connection.reconnect()) fail with an IOException. The cache loader first tries to query 'show create table', and on any Throwable it reconnects and retries once. If the retry also fails, this CanalParseException wraps the second IOException.","triggerScenarios":"tableMetaCache.getUnchecked(fullName) triggers CacheLoader.load(), which calls getTableMetaByDB(). If that throws (connection broken, query error), the catch(Throwable) block calls connection.reconnect() and retries getTableMetaByDB(). If the retry throws IOException, the CanalParseException is thrown. This means the connection to MySQL is truly unavailable even after reconnect.","commonSituations":"The MySQL server is down or unreachable when Canal tries to load table metadata (common during failover). The connection pool is exhausted. A network partition separates Canal from MySQL. The canal user lacks privileges to run 'show create table' / 'desc' on the table. The table name contains special characters that break the SQL.","solutions":["Verify MySQL connectivity: test the JDBC connection with the same credentials Canal uses.","Check that the canal user has SELECT privilege needed for 'show create table' on the target databases.","Ensure the MySQL server is healthy and not in a recovery/failover state.","If transient (during failover), Canal's outer retry loop should recover — increase connection retry settings if needed."],"exampleFix":"# before\ncanal.instance.master.address=10.0.0.5:3306\n\n# after — add connection retries and fallback\ncanal.instance.master.address=10.0.0.5:3306\ncanal.instance.master.retry.count=3\ncanal.instance.master.connect.timeout=10000","handlingStrategy":"retry","validationCode":"// Before loading table meta, verify the connection is alive\ntry {\n    mysqlConnection.query(\"SELECT 1\");\n} catch (IOException e) {\n    logger.warn(\"Connection dead before table meta load, reconnecting\");\n    mysqlConnection.reconnect();\n}","typeGuard":null,"tryCatchPattern":"// TableMetaCache loading is internal; configure retry at the parser level:\n// The cache loader already retries once. Add outer retry in the parser:\nint retries = 0;\nwhile (retries < 3) {\n    try {\n        TableMeta meta = tableMetaCache.getTableMeta(schema, table);\n        break;\n    } catch (CanalParseException e) {\n        retries++;\n        if (retries >= 3) throw e;\n        Thread.sleep(retries * 3000L);\n        connection.reconnect();\n    }\n}","preventionTips":["Monitor MySQL server availability — transient connection loss is the most common cause.","Configure JDBC autoReconnect and keepalive settings to maintain connection health.","Ensure the canal user has SELECT privileges needed for 'show create table' on all replicated schemas."],"tags":["mysql","table-meta","connection","retry-failed","cache"],"backgroundTag":null,"analyzedSha":"87be50e87686a3e8af08c368d0e1ffd1f59eb04a","analyzedAt":"2026-08-14T04:30:11.918Z","schemaVersion":2},"datasetVersion":"2026-08-14T05:17:29.042Z"}