kestra-io / kestra-io/plugin-debezium

mysql: `serverId` is `@NotNull` but documented as optional, and the Trigger example omits it

Open
#202 2 comments 0 reactions 1 assignee Claimed by @darkyellowcat View on GitHub
area/plugin good first issue
Dominant language
Java
Stars
5
Forks
11
Avg merge
2d 5h
Merged PRs (30d)
9

Description

## Summary

The MySQL `serverId` property is internally inconsistent across three places: `Capture` marks it `@NotNull` while `MysqlInterface` documents it as having a generated default, the `@PluginProperty(group = ...)` disagrees between the field and the interface getter, and the batch `Trigger`'s published `@Example` omits it entirely — which makes that copy-pasteable example fail at runtime with an opaque `NullPointerException`.

Surfaced during the documentation review in #199, which deliberately left code changes out of scope.

## Actual Behaviour

**1. `@NotNull` contradicts the documented default.**

`plugin-debezium-mysql/src/main/java/io/kestra/plugin/debezium/mysql/MysqlInterface.java:32-41` documents:

> "By default, a random number between 5400 and 6400 is generated, though the recommendation is to explicitly set a value."

But `mysql/Capture.java:64-66` declares:

```java
@NotNull
@PluginProperty(group = "main")
private Property serverId;
```

`@NotNull` makes the property mandatory, so the documented default can never apply. Either the annotation or the description is wrong.

**2. Group mismatch between field and interface getter.**

- `mysql/Capture.java:65` — `@PluginProperty(group = "main")`
- `MysqlInterface.java:39` — `@PluginProperty(dynamic = true, group = "advanced")`

Field annotations do not inherit from interface getters, so the two declarations drift and the UI grouping depends on which one the schema generator reads.

**3. The batch `Trigger` example omits the required property → runtime NPE.**

`mysql/Trigger.java:35-53` publishes a full runnable example with no `serverId`. `mysql/Trigger.java:97` builds a `Capture` from the trigger's own fields:

```java
Capture task = Capture.builder()
...
.serverId(this.serverId)
```

`mysql.Trigger.serverId` (line 61) carries **no** `@NotNull`, so a flow without it validates fine. `Capture.properties()` then does:

```java
props.setProperty("database.server.id", runContext.render(this.serverId).as(String.class).orElse(null));
```

`Properties.setProperty` is `Hashtable.put`, which throws `NullPointerException` on a null value. The published example therefore fails at runtime rather than at validation time, with a stack trace that names neither `serverId` nor the flow property that caused it.

`mysql/RealtimeTrigger.java:45` already includes `serverId` in its example — only the batch `Trigger` is missing it. PR #199 added it to the `Capture` example for exactly this reason.

## Expected Behaviour

- The `@NotNull` on `Capture.serverId` and the "a random number is generated by default" wording agree with each other.
- The `@PluginProperty` group is declared identically on the field and the interface getter.
- The batch `Trigger` example is runnable as published.
- If `serverId` is genuinely required for the trigger path, `mysql.Trigger` and `mysql.RealtimeTrigger` declare `@NotNull` too, so a missing value fails at flow-validation time with a clear message instead of surfacing as a `NullPointerException` from `Hashtable`.
- Regardless of the above, `Capture.properties()` should not call `setProperty` with a possibly-null value — guard it, or `.orElseThrow()` with a message naming the property and the fix.

## Reproducer

```yaml
id: mysql_trigger_no_serverid
namespace: company.team

tasks:
- id: send_data
type: io.kestra.plugin.core.log.Log
message: "{{ trigger.uris }}"

triggers:
- id: trigger
type: io.kestra.plugin.debezium.mysql.Trigger
snapshotMode: NEVER
hostname: 127.0.0.1
port: "3306"
username: "{{ secret('MYSQL_USERNAME') }}"
password: "{{ secret('MYSQL_PASSWORD') }}"
```

This is the example currently published on the `mysql.Trigger` documentation page (modulo the `type` fix in #199). It passes validation and fails when the trigger first evaluates.

## Logs / Stack Trace

Not captured; the expected failure originates from `java.util.Hashtable.put` via `Properties.setProperty` in `Capture.properties()` (`mysql/Capture.java:78`). Worth attaching a real trace when confirming the reproducer.

## Environment

- **Kestra version**: 1.3.16 (`kestraVersion` in `gradle.properties`)
- **Plugin version**: 1.4.7
- **Deployment**: n/a — source-level defect, reproducible on any deployment

## Acceptance Criteria

- [ ] `Capture.serverId`'s nullability and its `@Schema` description agree
- [ ] `@PluginProperty(group = ...)` matches between `mysql/Capture.java` and `MysqlInterface`
- [ ] `mysql/Trigger.java`'s `@Example` includes `serverId` and is runnable as published
- [ ] A missing `serverId` on a trigger fails with an actionable message, not a bare `NullPointerException`
- [ ] `Capture.properties()` no longer passes a possibly-null value to `Properties.setProperty`
- [ ] A test covers the missing-`serverId` trigger path and asserts the error message

## Additional Context

Flagged in the review of #199 (documentation-only PR). The SQL Server module has a separate, unrelated `serverId` problem tracked in its own issue: there the property exists but does nothing.

---
*[View as Artifact](https://claude.ai/code/artifact/66907e1c-200f-466d-9901-26a9e7de6d51)*

Contributor guide

No contributing guide indexed for this repository

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.