{"record":{"id":"5516109eb8c3cd9d","repo":"apache/seatunnel","slug":"invalid-table-url-format-s-expected-format-h","errorCode":null,"errorMessage":"Invalid table URL format: '%s'. Expected format: http://host/api/metalakes/{metalake}/catalogs/{catalog}/schemas/{schema}/tables/{table}","messagePattern":"Invalid table URL format: '(.+?)'\\. Expected format: http://host/api/metalakes/(.+?)/catalogs/(.+?)/schemas/(.+?)/tables/(.+?)","errorType":"exception","errorClass":"SeaTunnelRuntimeException","httpStatus":null,"severity":"error","filePath":"seatunnel-api/src/main/java/org/apache/seatunnel/api/metalake/gravitino/GravitinoClient.java","lineNumber":116,"sourceCode":"    }\n\n    @Override\n    public TablePath getTableSchemaPath(String schemaHttpUrl) {\n        if (schemaHttpUrl == null || schemaHttpUrl.isEmpty()) {\n            throw new SeaTunnelRuntimeException(\n                    ERROR_INVALID_TABLE_URL, \"Table URL cannot be null or empty\");\n        }\n        final Matcher matcher = getMatcher(schemaHttpUrl);\n        String catalogName = matcher.group(1);\n        String schemaName = matcher.group(2);\n        String tableName = matcher.group(3);\n        return TablePath.of(catalogName, schemaName, tableName);\n    }\n\n    private Matcher getMatcher(String schemaHttpUrl) {\n        Matcher matcher = TABLE_URL_PATTERN.matcher(schemaHttpUrl);\n        if (!matcher.find()) {\n            throw new SeaTunnelRuntimeException(\n                    ERROR_INVALID_TABLE_URL,\n                    String.format(\n                            \"Invalid table URL format: '%s'. \"\n                                    + \"Expected format: http://host/api/metalakes/{metalake}/catalogs/{catalog}/schemas/{schema}/tables/{table}\",\n                            schemaHttpUrl));\n        }\n        return matcher;\n    }\n\n    /**\n     * Execute HTTP GET request and return parsed JSON response. Implements retry with exponential\n     * backoff for transient failures.\n     *\n     * @param url the request URL\n     * @return parsed JSON root node\n     */\n    private JsonNode executeGetRequest(String url) {\n        for (int attempt = 1; attempt <= MAX_RETRY_ATTEMPTS; attempt++) {","sourceCodeStart":98,"sourceCodeEnd":134,"githubUrl":"https://github.com/apache/seatunnel/blob/cf67b549a7a6c35fa0beb12d83c62892427ea919/seatunnel-api/src/main/java/org/apache/seatunnel/api/metalake/gravitino/GravitinoClient.java#L98-L134","documentation":"SeaTunnelRuntimeException (ERROR_INVALID_TABLE_URL) thrown by GravitinoClient.getMatcher when the schemaHttpUrl does not match TABLE_URL_PATTERN, i.e. it is not of the form http://host/api/metalakes/{metalake}/catalogs/{catalog}/schemas/{schema}/tables/{table}.","triggerScenarios":"Calling getTableSchemaPath (directly or via tableSchema flows) with a URL missing the /api/metalakes/ path, using a different API version path, having trailing segments, or pointing at a non-table resource (e.g. a catalogs or schemas URL).","commonSituations":"Configured Gravitino server uses a versioned or proxied path prefix; user pasted the catalog or schema URL instead of the table URL; trailing slash or query string appended; HTTP vs HTTPS host mismatch is fine but path changes are not.","solutions":["Pass the exact table URL: http(s)://host/api/metalakes/{metalake}/catalogs/{catalog}/schemas/{schema}/tables/{table}.","Check for trailing slashes or query strings and remove them.","If your server uses a custom path prefix, verify it matches the regex TABLE_URL_PATTERN or normalize the URL before calling.","Log/print the offending URL and test it against the expected regex."],"exampleFix":"// before\nclient.getTableSchemaPath(\"http://host/api/metalakes/m1/catalogs/c1/schemas/s1\");\n// after\nclient.getTableSchemaPath(\"http://host/api/metalakes/m1/catalogs/c1/schemas/s1/tables/t1\");","handlingStrategy":"validation","validationCode":"static final Pattern P = Pattern.compile(\"https?://[^/]+/api/metalakes/[^/]+/catalogs/[^/]+/schemas/[^/]+/tables/[^/]+/?$\");\nstatic boolean isValidTableUrl(String u) { return u != null && P.matcher(u).matches(); }\n// if (!isValidTableUrl(tableUrl)) throw new IllegalArgumentException(tableUrl);","typeGuard":null,"tryCatchPattern":"try {\n    return client.getTableSchemaPath(url);\n} catch (SeaTunnelRuntimeException e) {\n    if (e.getMessage().startsWith(\"Invalid table URL format\")) {\n        LOG.error(\"URL {} does not match expected Gravitino table URL shape\", url);\n    }\n    throw e;\n}","preventionTips":["Store full table URLs (through /tables/{table}), not catalog/schema URLs.","Strip trailing slashes and query strings before calling.","Normalize versioned API prefixes to match the expected pattern.","Unit-test URL construction with real Gravitino examples."],"tags":["url","regex","validation","gravitino"],"backgroundTag":"invalid-url-format","analyzedSha":"cf67b549a7a6c35fa0beb12d83c62892427ea919","analyzedAt":"2026-09-10T21:44:55.265Z","contentChangedAt":"2026-09-10T21:44:55.265Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}