{"record":{"id":"84b0b237e1bd597b","repo":"apache/seatunnel","slug":"option-field-delimiter-cannot-be-empty-84b0b2","errorCode":null,"errorMessage":"Option 'field_delimiter' cannot be empty","messagePattern":"Option 'field_delimiter' cannot be empty","errorType":"validation","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"seatunnel-connectors-v2/connector-google-pubsub/src/main/java/org/apache/seatunnel/connectors/seatunnel/google/pubsub/config/GooglePubSubSourceConfig.java","lineNumber":63,"sourceCode":"        String credentialsPath = config.get(GooglePubSubSourceOptions.CREDENTIALS_PATH);\n        String emulatorHost = config.get(GooglePubSubSourceOptions.EMULATOR_HOST);\n        MessageFormat format = config.get(GooglePubSubSourceOptions.FORMAT);\n        String fieldDelimiter = config.get(GooglePubSubSourceOptions.FIELD_DELIMITER);\n        Long maxOutstandingMessages =\n                config.get(GooglePubSubSourceOptions.MAX_OUTSTANDING_MESSAGES);\n        Long maxOutstandingBytes = config.get(GooglePubSubSourceOptions.MAX_OUTSTANDING_BYTES);\n        Integer parallelPullCount = config.get(GooglePubSubSourceOptions.PARALLEL_PULL_COUNT);\n\n        requireNonBlank(projectId, GooglePubSubSourceOptions.PROJECT_ID.key());\n        requireNonBlank(subscription, GooglePubSubSourceOptions.SUBSCRIPTION.key());\n        requireNonBlankIfPresent(credentialsPath, GooglePubSubSourceOptions.CREDENTIALS_PATH.key());\n        requireNonBlankIfPresent(emulatorHost, GooglePubSubSourceOptions.EMULATOR_HOST.key());\n        if (credentialsPath != null && emulatorHost != null) {\n            throw new IllegalArgumentException(\n                    \"Options 'credentials_path' and 'emulator_host' cannot be configured together\");\n        }\n        if (format == MessageFormat.TEXT && fieldDelimiter.isEmpty()) {\n            throw new IllegalArgumentException(\"Option 'field_delimiter' cannot be empty\");\n        }\n        requirePositive(\n                maxOutstandingMessages, GooglePubSubSourceOptions.MAX_OUTSTANDING_MESSAGES.key());\n        requirePositive(maxOutstandingBytes, GooglePubSubSourceOptions.MAX_OUTSTANDING_BYTES.key());\n        requirePositive(parallelPullCount, GooglePubSubSourceOptions.PARALLEL_PULL_COUNT.key());\n\n        return GooglePubSubSourceConfig.builder()\n                .projectId(projectId)\n                .subscription(subscription)\n                .credentialsPath(credentialsPath)\n                .emulatorHost(emulatorHost)\n                .format(format)\n                .fieldDelimiter(fieldDelimiter)\n                .maxOutstandingMessages(maxOutstandingMessages)\n                .maxOutstandingBytes(maxOutstandingBytes)\n                .parallelPullCount(parallelPullCount)\n                .build();\n    }","sourceCodeStart":45,"sourceCodeEnd":81,"githubUrl":"https://github.com/apache/seatunnel/blob/cf67b549a7a6c35fa0beb12d83c62892427ea919/seatunnel-connectors-v2/connector-google-pubsub/src/main/java/org/apache/seatunnel/connectors/seatunnel/google/pubsub/config/GooglePubSubSourceConfig.java#L45-L81","documentation":"Thrown by GooglePubSubSourceConfig.from when the connector is built with format=TEXT but field_delimiter resolves to an empty string. The TEXT format splits message payloads on this delimiter, so an empty value would make parsing meaningless. This is an eager configuration validation to fail fast at source construction instead of at read time.","triggerScenarios":"Calling GooglePubSubSourceConfig.from (directly or via the SeaTunnel source factory) with GooglePubSubSourceOptions.MESSAGE_FORMAT set to TEXT and GooglePubSubSourceOptions.FIELD_DELIMITER set to an empty string \"\".","commonSituations":"Users set field_delimiter = \"\" in the HOCON config to try to disable delimiter-based splitting, or a template/variable interpolation yields an empty value while message_format is TEXT.","solutions":["Set a non-empty field_delimiter (e.g. \",\" or \"\\t\") in the source config when message_format = TEXT.","If no delimiter splitting is desired, switch message_format to JSON instead of TEXT.","Verify no environment-variable or placeholder expansion is blanking the field_delimiter value before it reaches the connector."],"exampleFix":"// before\nfield_delimiter = \"\"\nmessage_format = TEXT\n// after\nfield_delimiter = \",\"\nmessage_format = TEXT","handlingStrategy":"validation","validationCode":"String delimiter = config.get(\"field_delimiter\");\nString format = config.get(\"message_format\");\nif (\"text\".equalsIgnoreCase(format) && (delimiter == null || delimiter.isEmpty())) {\n    throw new IllegalArgumentException(\"field_delimiter must be non-empty when message_format is TEXT\");\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Always pair TEXT format with an explicit delimiter in config templates.","Use JSON format when no delimiter splitting is intended.","Add a pre-submit config lint that rejects empty string options."],"tags":["config-validation","google-pubsub","java"],"backgroundTag":"empty-required-field","analyzedSha":"cf67b549a7a6c35fa0beb12d83c62892427ea919","analyzedAt":"2026-09-10T21:44:55.265Z","contentChangedAt":"2026-09-10T21:44:55.265Z","schemaVersion":2},"datasetVersion":"2026-09-14T11:17:12.474Z"}