Skip to content

out_s3, out_chronicle: grow log_key buffer to avoid dropping oversized values - #12137

Open
vitaly-sinev wants to merge 2 commits into
fluent:masterfrom
vitaly-sinev:out-plugins-log-key-grow
Open

out_s3, out_chronicle: grow log_key buffer to avoid dropping oversized values#12137
vitaly-sinev wants to merge 2 commits into
fluent:masterfrom
vitaly-sinev:out-plugins-log-key-grow

Conversation

@vitaly-sinev

@vitaly-sinev vitaly-sinev commented Jul 22, 2026

Copy link
Copy Markdown

Problem

The log_key extraction paths in out_s3 and out_chronicle allocate a scratch buffer of bytes + bytes / 4 once and never grow it. When the selected log_key value is a non-string (number/array/object) whose JSON encoding does not fit in the remaining space, flb_msgpack_to_json() fails and the code simply breaks out of the loop:

ret = flb_msgpack_to_json(val_buf + val_offset, msgpack_size - val_offset, &val, ...);
if (ret < 0) {
    break;
}

As a result the oversized value is silently dropped (and, depending on timing, could previously be emitted truncated). This is a pre-existing data-loss bug independent of any formatting change.

Fix

Grow the scratch buffer and retry the conversion until the value fits, so an oversized log_key value is neither truncated nor dropped. The retry also guards the remaining size so flb_msgpack_to_json() is never called with a zero-length buffer.

  • out_s3: on allocation failure it uses the function's existing alloc_error path.
  • out_chronicle: on allocation failure it frees and returns NULL.

Testing

  • Builds cleanly with -DFLB_OUT_S3=On -DFLB_OUT_CHRONICLE=On (full fluent-bit binary).

Context

Surfaced during review of #12129 / #12133. #12133 makes flb_msgpack_to_json() signal truncation as a negative value (matching its contract); this PR makes these two callers actually recover from it. The two PRs are independent — this fix works whether the helper returns 0 or -1 on overflow (it checks ret <= 0).


Fluent Bit is licensed under Apache 2.0, by submitting this pull request I understand that this code will be released under the terms of that license.

🤖 Generated with Claude Code

Summary by CodeRabbit

  • Bug Fixes
    • Improved handling of oversized log values during msgpack-to-JSON serialization for Chronicle and S3 outputs.
    • Added automatic retry with a growable buffer to prevent truncated or incomplete values.
    • Improved safety when additional memory cannot be allocated by aborting cleanly so data can be retried instead of emitting partial payloads.

@coderabbitai

coderabbitai Bot commented Jul 22, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

Chronicle and S3 now resize scratch buffers and retry JSON serialization when log-key values exceed the initial capacity. Allocation failures free the buffer and abort extraction.

Changes

Log-key serialization

Layer / File(s) Summary
Grow-and-retry JSON serialization
plugins/out_chronicle/chronicle.c, plugins/out_s3/s3.c
Both plugins grow scratch buffers for oversized non-BIN/STR log-key values. They retry serialization until it fits or allocation fails. Failure cleanup returns NULL and prevents partial output.

Estimated code review effort: 2 (Simple) | ~10 minutes

Possibly related PRs

Suggested reviewers: edsiper, cosmo0920

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly identifies both affected plugins and the main change to prevent oversized log_key values from being dropped.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (1)
plugins/out_chronicle/chronicle.c (1)

604-623: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Apply the required control-block brace style consistently.

  • plugins/out_chronicle/chronicle.c#L604-L623: move opening braces for the new while and if blocks onto the following line.
  • plugins/out_s3/s3.c#L3695-L3715: make the same change for the new retry-loop blocks.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@plugins/out_chronicle/chronicle.c` around lines 604 - 623, Apply the
project’s brace style to the new control blocks: in
plugins/out_chronicle/chronicle.c lines 604-623, update the while and if blocks;
in plugins/out_s3/s3.c lines 3695-3715, make the same adjustment for each new
retry-loop block. Move each opening brace onto the following line without
changing control flow.

Source: Coding guidelines

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@plugins/out_s3/s3.c`:
- Around line 3707-3715: Update the allocation-failure handling in the decoder
path around alloc_error so any failure after records have been appended cannot
return a partial payload. After destroying the decoder, free val_buf and return
NULL whenever alloc_error is set, regardless of val_offset or previously decoded
data.

---

Nitpick comments:
In `@plugins/out_chronicle/chronicle.c`:
- Around line 604-623: Apply the project’s brace style to the new control
blocks: in plugins/out_chronicle/chronicle.c lines 604-623, update the while and
if blocks; in plugins/out_s3/s3.c lines 3695-3715, make the same adjustment for
each new retry-loop block. Move each opening brace onto the following line
without changing control flow.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 67c22f54-452d-47a4-a28e-2dad486fe111

📥 Commits

Reviewing files that changed from the base of the PR and between c830fb6 and f25bf78.

📒 Files selected for processing (2)
  • plugins/out_chronicle/chronicle.c
  • plugins/out_s3/s3.c

Comment thread plugins/out_s3/s3.c

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: f25bf7808d

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment thread plugins/out_s3/s3.c
Comment on lines +3709 to +3710
alloc_error = 1;
break;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Return NULL when S3 log_key growth fails

For S3 chunks using log_key, if a later non-string value needs this buffer growth and flb_realloc() fails after earlier records have already advanced val_offset, setting alloc_error only exits the decoder loop; the function then falls through and creates an SDS from the partial val_buf whenever val_offset != 0. The flush path treats that non-NULL chunk as data to upload, so the current and remaining records can be dropped while the output reports success; free the buffer and return NULL on this allocation failure instead of falling through with partial data.

Useful? React with 👍 / 👎.

@vitaly-sinev

Copy link
Copy Markdown
Author

Good catch (both @coderabbitai and @chatgpt-codex-connector) — fixed: on alloc_error out_s3 now frees the scratch buffer and returns NULL after destroying the decoder, instead of returning a partial payload. (out_chronicle already returned NULL on growth failure.) Pushed.

@chatgpt-codex-connector

Copy link
Copy Markdown

To use Codex here, create a Codex account and connect to github.

@coderabbitai

coderabbitai Bot commented Jul 22, 2026

Copy link
Copy Markdown

Tip

For best results, initiate chat on the files or code changes.

@vitaly-sinev Thanks for fixing this. Returning NULL after releasing the scratch buffer and decoder prevents emitting a partial payload on allocation failure.

🐇✅


If you found this review helpful, would you consider giving us a shout-out on X?

Thank you for using CodeRabbit!

vitaly-sinev and others added 2 commits August 1, 2026 18:47
The log_key extraction buffer was sized bytes + bytes/4 and never grown. A
non-string log_key value whose JSON form exceeded the remaining space made
flb_msgpack_to_json() fail; the code only broke out of the loop, so the
oversized value was silently dropped (and, before that, could be emitted
truncated).

Grow the scratch buffer and retry the conversion until the value fits, so
the value is neither truncated nor dropped. The guard on the remaining size
also avoids calling flb_msgpack_to_json() with a zero-length buffer.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Signed-off-by: v.sinev <vit.phantom@gmail.com>
The log_key extraction buffer was sized bytes + bytes/4 and never grown. A
non-string log_key value whose JSON form exceeded the remaining space made
flb_msgpack_to_json() fail; the code only broke out of the loop, so the
oversized value was silently dropped.

Grow the scratch buffer and retry the conversion until the value fits, so
the value is neither truncated nor dropped. The guard on the remaining size
also avoids calling flb_msgpack_to_json() with a zero-length buffer.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Signed-off-by: v.sinev <vit.phantom@gmail.com>
@vitaly-sinev
vitaly-sinev force-pushed the out-plugins-log-key-grow branch from 032f864 to c476849 Compare August 1, 2026 16:18

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (3)
plugins/out_s3/s3.c (3)

4504-4506: 📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Correct the configuration descriptions.

The format parser accepts arrow, but the format description omits it. The compression parser accepts none, while arrow and deprecated parquet select formats rather than compression codecs. Separate these legacy aliases from the codec list.

Also applies to: 4577-4580

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@plugins/out_s3/s3.c` around lines 4504 - 4506, Update the format and
compression configuration descriptions near the output-format options to list
arrow as a supported format, and describe compression as accepting none, snappy,
zstd, and gzip codecs. Keep arrow and deprecated parquet identified as format
aliases rather than compression codecs, and state the default consistently.

1020-1047: 🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

Reject conflicting format selectors.

When format=arrow and compression=parquet are both configured, these branches call enable_parquet_format() and replace the explicit format. The reverse combination has the same problem. Reject mismatches, or give the explicit format property precedence.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@plugins/out_s3/s3.c` around lines 1020 - 1047, Update the format-selection
logic around enable_parquet_format() and enable_arrow_format() to detect when
compression-based selectors conflict with an explicitly configured format.
Reject mismatches with an error, or ensure the explicit format takes precedence;
preserve valid matching configurations and existing deprecation handling.

1785-1807: 🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

Retry backlog chunks after conversion failure.

The live path returns FLB_RETRY, but this path continues to s3_put_object() after columnar conversion fails. It can store JSON under a Parquet or Arrow format. If generic compression fails, it can also send an uncompressed body while create_headers() still advertises Content-Encoding. Return failure and retain the chunk for retry, or update the per-request format and headers before fallback.

As per coding guidelines, verify backlog/live-ingestion parity.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@plugins/out_s3/s3.c` around lines 1785 - 1807, Update the failure handling in
the columnar conversion and generic compression branches before s3_put_object():
match the live path by returning FLB_RETRY and retaining the backlog chunk when
conversion or compression fails, rather than uploading fallback data with stale
format or Content-Encoding headers. Verify the backlog path uses the same retry
behavior as live ingestion.

Source: Coding guidelines

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Outside diff comments:
In `@plugins/out_s3/s3.c`:
- Around line 4504-4506: Update the format and compression configuration
descriptions near the output-format options to list arrow as a supported format,
and describe compression as accepting none, snappy, zstd, and gzip codecs. Keep
arrow and deprecated parquet identified as format aliases rather than
compression codecs, and state the default consistently.
- Around line 1020-1047: Update the format-selection logic around
enable_parquet_format() and enable_arrow_format() to detect when
compression-based selectors conflict with an explicitly configured format.
Reject mismatches with an error, or ensure the explicit format takes precedence;
preserve valid matching configurations and existing deprecation handling.
- Around line 1785-1807: Update the failure handling in the columnar conversion
and generic compression branches before s3_put_object(): match the live path by
returning FLB_RETRY and retaining the backlog chunk when conversion or
compression fails, rather than uploading fallback data with stale format or
Content-Encoding headers. Verify the backlog path uses the same retry behavior
as live ingestion.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: a018d9b3-a95c-4d33-b167-304987e43903

📥 Commits

Reviewing files that changed from the base of the PR and between 032f864 and c476849.

📒 Files selected for processing (2)
  • plugins/out_chronicle/chronicle.c
  • plugins/out_s3/s3.c
🚧 Files skipped from review as they are similar to previous changes (1)
  • plugins/out_chronicle/chronicle.c

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant