# Metricbeat SQL Module with cursor rereading rows

**URL:** <https://discuss.elastic.co/t/metricbeat-sql-module-with-cursor-rereading-rows/387286>\
**Category:** Beats\
**Tags:** metricbeat\
**Created:** [June 24, 2026, 10:16pm UTC](https://discuss.elastic.co/t/metricbeat-sql-module-with-cursor-rereading-rows/387286 "2026-06-24T22:16:43Z")\
**Posts on this page:** 4\
**Page:** 1

<div class="post-metadata">

**Author:** ![lpeter](https://sea2.discourse-cdn.com/elastic/user_avatar/discuss.elastic.co/lpeter/32/99176_2.png) [@lpeter](https://discuss.elastic.co/u/lpeter)\
**Post date:** [June 24, 2026, 10:16pm UTC](https://discuss.elastic.co/t/metricbeat-sql-module-with-cursor-rereading-rows/387286/1 "2026-06-24T22:16:44Z")

</div>

Hello!

I think I may have hit a bug where Metricbeat SQL module's cursor state can be read from the wrong Elastic Agent component data path, causing cursor reset and duplicate ingestion.

This is on Elastic Agent / Metricbeat 9.4.2.

This was first observed through a custom integration package, but the package only renders a normal Elastic Agent `sql/metrics` input using the upstream Metricbeat SQL cursor config.  
The input has a stable `cursor.state_id`, stable query text, and stable cursor column/direction.

What happens:

1. SQL cursor runs normally and advances.
2. I change an unrelated metric integration in the same Agent policy.
3. After the policy reload, the SQL cursor sometimes starts from its default again and rereads rows.

In the logs I can see SQL cursor registries being created under different component paths. One registry was created under the expected `sql/metrics-default` path:

```plaintext
Jun 24, 2026 @ 18:39:08.034 component.id=sql/metrics-default
Created shared SQL cursor registry at /opt/Elastic/Agent/data/elastic-agent-9.4.2-dd9ee6/run/sql/metrics-default/sql-cursor (ptr=0x3348fa9e55c0)

```

Later, another SQL cursor registry was created under the `system/metrics-default` component path and then used by `sql/metrics-default`:

```plaintext
Jun 24, 2026 @ 18:40:04.553 component.id=system/metrics-default
Created shared SQL cursor registry at /opt/Elastic/Agent/data/elastic-agent-9.4.2-dd9ee6/run/system/metrics-default/sql-cursor (ptr=0x3348fad47e60)

Jun 24, 2026 @ 18:40:04.553 component.id=sql/metrics-default
Using shared SQL cursor registry at 0x3348fad47e60

```

For one cursor, the same `state_key` was already advanced immediately before this happened:

```plaintext
Jun 24, 2026 @ 18:39:10.912 component.id=sql/metrics-default
Cursor fetch completed: state_key=sql-cursor::fba2dd494f9d31a0 cursor_before=0 cursor_after=79 rows=79

```

After the `system/metrics-default` registry was used, the same `state_key` started from 0 again and reread the same rows:

```plaintext
Jun 24, 2026 @ 18:40:04.568 component.id=system/metrics-default
Finished loading transaction log file for '/opt/Elastic/Agent/data/elastic-agent-9.4.2-dd9ee6/run/system/metrics-default/sql-cursor/cursor-state'. Active transaction id=0

Jun 24, 2026 @ 18:40:06.152 component.id=sql/metrics-default
Cursor fetch start: driver=mysql timeout=1m0s state_key=sql-cursor::fba2dd494f9d31a0 cursor=0

Jun 24, 2026 @ 18:40:06.171 component.id=sql/metrics-default
Cursor fetch completed: state_key=sql-cursor::fba2dd494f9d31a0 cursor_before=0 cursor_after=79 rows=79

```

The interesting part is that this seems limited to the Agent OTel runtime. With this extra Agent config, I have not been able to reproduce the issue so far:

```yaml
agent.internal:
  runtime:
    metricbeat:
      sql/metrics: process

```

So my vague guess is that the SQL cursor registry may be using a shared/global `path.data` value that can point at another Metricbeat component under the OTel runtime.

Does this look like a bug in the Metricbeat SQL cursor implementation, or is there some expected Agent/OTel behavior I am missing?

---

<div class="post-metadata">

**Author:** ![TiagoQueiroz](https://sea2.discourse-cdn.com/elastic/user_avatar/discuss.elastic.co/tiagoqueiroz/32/107061_2.png) [@TiagoQueiroz](https://discuss.elastic.co/u/TiagoQueiroz)\
**Post date:** [June 24, 2026, 10:31pm UTC](https://discuss.elastic.co/t/metricbeat-sql-module-with-cursor-rereading-rows/387286/2 "2026-06-24T22:31:38Z")

</div>

Hey @lpeter thanks for reporting this!

This seems to be a bug in how the Otel runtime is handling the state store for Metricbeat (maybe for all beats 😱).

I'll take a look/get someone to take a look at it.

In the mean time, could you share the custom integration you're using? Having the same integration code will be very helpful.

---

<div class="post-metadata">

**Author:** ![TiagoQueiroz](https://sea2.discourse-cdn.com/elastic/user_avatar/discuss.elastic.co/tiagoqueiroz/32/107061_2.png) [@TiagoQueiroz](https://discuss.elastic.co/u/TiagoQueiroz)\
**Post date:** [June 24, 2026, 11:18pm UTC](https://discuss.elastic.co/t/metricbeat-sql-module-with-cursor-rereading-rows/387286/3 "2026-06-24T23:18:53Z")

</div>

I managed to reproduce it, I'll create a GitHub issue.

---

<div class="post-metadata">

**Author:** ![lpeter](https://sea2.discourse-cdn.com/elastic/user_avatar/discuss.elastic.co/lpeter/32/99176_2.png) [@lpeter](https://discuss.elastic.co/u/lpeter)\
**Post date:** [June 25, 2026, 7:39am UTC](https://discuss.elastic.co/t/metricbeat-sql-module-with-cursor-rereading-rows/387286/4 "2026-06-25T07:39:31Z")

</div>

Hi @TiagoQueiroz!

Thanks for looking into it so quicky. I see you managed to reproduce it without the custom integration, so probably there's not much use for it, but here it is anyway: [GitHub - lpeter91/elastic-sql-cursor-input-integration · GitHub](https://github.com/lpeter91/elastic-sql-cursor-input-integration) (It's basically a mostly vibe-coded fork of the official SQL input integration, so do whatever you will with it.)

Here's the corresponding GitHub issue for future generations: [Metricbeat receivers share the same store and "corrupt" data · Issue #15154 · elastic/elastic-agent · GitHub](https://github.com/elastic/elastic-agent/issues/15154)
