{"record":{"id":"23ce3d10913b37ab","repo":"apache/seatunnel","slug":"sourceoptions-startup-specific-offset-file-key","errorCode":null,"errorMessage":"'${SourceOptions.STARTUP_SPECIFIC_OFFSET_FILE.key()}' and '${SourceOptions.STARTUP_SPECIFIC_OFFSET_POS.key()}' must be configured together when '${SourceOptions.STARTUP_MODE_KEY}' is 'specific'.","messagePattern":"'(.+?)' and '(.+?)' must be configured together when '(.+?)' is 'specific'\\.","errorType":"validation","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"seatunnel-connectors-v2/connector-cdc/connector-cdc-mysql/src/main/java/org/apache/seatunnel/connectors/seatunnel/cdc/mysql/source/MySqlIncrementalSource.java","lineNumber":108,"sourceCode":"        return new StartupConfig(\n                startupMode,\n                config.get(SourceOptions.STARTUP_SPECIFIC_OFFSET_FILE),\n                config.get(SourceOptions.STARTUP_SPECIFIC_OFFSET_POS),\n                config.get(SourceOptions.STARTUP_TIMESTAMP));\n    }\n\n    /*\n     * Debezium's MySqlOffsetContext.Loader requires file and pos for a specific startup offset.\n     * GTID and skip fields are optional metadata on that same offset, not an alternative anchor.\n     */\n    private static Map<String, String> createSpecificStartupOffset(ReadonlyConfig config) {\n        Optional<String> gtidSet = getValidatedGtidSet(config);\n        boolean hasFile =\n                config.getOptional(SourceOptions.STARTUP_SPECIFIC_OFFSET_FILE).isPresent();\n        boolean hasPos = config.getOptional(SourceOptions.STARTUP_SPECIFIC_OFFSET_POS).isPresent();\n\n        if (hasFile != hasPos) {\n            throw new IllegalArgumentException(\n                    String.format(\n                            \"'%s' and '%s' must be configured together when '%s' is 'specific'.\",\n                            SourceOptions.STARTUP_SPECIFIC_OFFSET_FILE.key(),\n                            SourceOptions.STARTUP_SPECIFIC_OFFSET_POS.key(),\n                            SourceOptions.STARTUP_MODE_KEY));\n        }\n\n        if (!hasFile) {\n            throw new IllegalArgumentException(\n                    String.format(\n                            \"'%s' requires '%s' with '%s' when the mode is 'specific'.\",\n                            SourceOptions.STARTUP_MODE_KEY,\n                            SourceOptions.STARTUP_SPECIFIC_OFFSET_FILE.key(),\n                            SourceOptions.STARTUP_SPECIFIC_OFFSET_POS.key()));\n        }\n\n        long skipEvents =\n                getNonNegativeSkipValue(","sourceCodeStart":90,"sourceCodeEnd":126,"githubUrl":"https://github.com/apache/seatunnel/blob/cf67b549a7a6c35fa0beb12d83c62892427ea919/seatunnel-connectors-v2/connector-cdc/connector-cdc-mysql/src/main/java/org/apache/seatunnel/connectors/seatunnel/cdc/mysql/source/MySqlIncrementalSource.java#L90-L126","documentation":"MySqlIncrementalSource validates that when startup.mode=specific, both startup.specific-offset.file and startup.specific-offset.pos are provided. If exactly one of them is set (hasFile != hasPos), the pair is inconsistent and the connector refuses to build a binlog offset, throwing this IllegalArgumentException at source creation time.","triggerScenarios":"Calling createSpecificStartupOffset via createStartupConfig with startup.mode='specific' where only startup.specific-offset.file OR only startup.specific-offset.pos is configured.","commonSituations":"User adds a binlog filename but forgets the position (or vice versa); config template copies only one key; YAML indentation drops the second key; user assumes file alone is sufficient like some other CDC tools.","solutions":["Set both startup.specific-offset.file and startup.specific-offset.pos together in the source config","If you don't need an exact offset, use startup.mode='initial' or 'latest' instead of 'specific'","Verify keys are spelled correctly and nested under the same source block in the HOCON/YAML config"],"exampleFix":"// before\nstartup {\n  mode = \"specific\"\n  specific-offset.file = \"mysql-bin.000003\"\n}\n// after\nstartup {\n  mode = \"specific\"\n  specific-offset.file = \"mysql-bin.000003\"\n  specific-offset.pos = 4\n}","handlingStrategy":"validation","validationCode":"boolean hasFile = config.hasPath(\"startup.specific-offset.file\");\nboolean hasPos = config.hasPath(\"startup.specific-offset.pos\");\nif (hasFile != hasPos) {\n    throw new IllegalArgumentException(\"startup.specific-offset.file and .pos must be set together\");\n}","typeGuard":"if (!(typeof file === \"string\" && file.length > 0) || !(typeof pos === \"number\" && pos > 0)) throw new Error(\"file and pos must both be set\");","tryCatchPattern":"try { source = new MySqlIncrementalSource<>(options); } catch (IllegalArgumentException e) { LOG.error(\"Invalid specific startup offset pair: {}\", e.getMessage()); throw new ConfigException(e); }","preventionTips":["Always set file and pos as a pair in templates","Write a config linter/check before job submission","Prefer startup.mode='latest'/'initial' unless exact offset resume is required"],"tags":["cdc","mysql","config-validation"],"backgroundTag":"conflicting-config-options","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"}