fix(jobs): scrub build logs to valid UTF-8 before persisting by ChiragAgg5k · Pull Request #13706 · appwrite/appwrite · GitHub
Skip to content

fix(jobs): scrub build logs to valid UTF-8 before persisting - #13706

Merged
ChiragAgg5k merged 2 commits into
mainfrom
fix/jobs-build-logs-utf8
Sep 15, 2026
Merged

ChiragAgg5k merged 2 commits into
mainfrom
fix/jobs-build-logs-utf8

Conversation

@ChiragAgg5k

Copy link
Copy Markdown
Member

Summary

Fixes CLOUD-3QXN: SQLSTATE[HY000]: General error: 1366 Incorrect string value: '\x82 gzip...' for column 'buildLogs' in the jobs worker, ~90 events over the last two weeks and still ongoing.

Two ways invalid UTF-8 reaches buildLogs. A build step can print raw binary (the gzip bytes in the Sentry title), and truncate() keeps the last APP_LOG_LENGTH_LIMIT bytes with substr, which can land inside a multibyte character. MySQL rejects either on write, so onLog throws and the deployment's build logs stop updating.

truncate() now passes the result through mb_scrub(). Every buildLogs write in this worker goes through it (the log chunk, the exit trailer, and cloud's site-distribution override), so this one spot covers all of them.

Testing

Pint passes. No test added for a one-line sanitisation.

Build output can contain raw binary, and truncating to the last N bytes can split a multibyte character. MySQL rejects both, so the log callback threw and the deployment's build logs stopped updating (CLOUD-3QXN).
@greptile-apps

greptile-apps Bot commented Sep 15, 2026 •

Copy link
Copy Markdown
Contributor


return \substr($logs, -$limit);
// Build output can be binary, and the byte cut can split a multibyte character; MySQL rejects either.
return \mb_scrub($logs, 'UTF-8');

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

P2 Missing Behavioral Regression Coverage

This production-incident fix has no behavioral regression coverage, so a later removal or reordering of the scrub could silently restore failed build-log persistence. Add a worker-level test that processes raw invalid bytes and a multibyte character split at the size boundary, then verifies that the persisted buildLogs is valid UTF-8 and remains bounded. Do not merely unit-test mb_scrub() or mirror this helper's implementation.

Knowledge Base Used: Functions and execution processing

Prompt To Fix With AI
This is a comment left during a code review.
Path: src/Appwrite/Platform/Modules/Functions/Workers/Jobs.php
Line: 846

Comment:
**Missing Behavioral Regression Coverage**

This production-incident fix has no behavioral regression coverage, so a later removal or reordering of the scrub could silently restore failed build-log persistence. Add a worker-level test that processes raw invalid bytes and a multibyte character split at the size boundary, then verifies that the persisted `buildLogs` is valid UTF-8 and remains bounded. Do not merely unit-test `mb_scrub()` or mirror this helper's implementation.

**Knowledge Base Used:** [Functions and execution processing](https://app.greptile.com/appwrite/-/custom-context/knowledge-base/appwrite/appwrite/-/docs/functions-execution-api.md)

---

For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.

Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

Fix in Claude Code Fix in Codex

@ChiragAgg5k
ChiragAgg5k merged commit 6662a94 into main Sep 15, 2026
49 checks passed
@ChiragAgg5k
ChiragAgg5k deleted the fix/jobs-build-logs-utf8 branch September 15, 2026 14:03
@github-actions

Copy link
Copy Markdown

✨ Benchmark results

Comparing main (before) → fix/jobs-build-logs-utf8 (after).

Metric Before After Change
🚀 Requests/sec 240.76 239.15 ⚪ -0.7%
⏱️ Latency P50 73.53 ms 74.04 ms ⚪ +0.7%
⏱️ Latency P95 169.57 ms 167.88 ms ⚪ -1%
Per-scenario breakdown & investigation details

Metrics below reflect the current branch (after). Δ P95 compares against the base.

Scenario P50 (ms) P95 (ms) Requests RPS Δ P95 (ms)
API total 74.04 167.88 14,820 239.15 -1.69
Account 138.74 256.57 780 13.31 -5.55
TablesDB 71.27 129.18 8,060 132.82 -1.24
Storage 68.68 149.43 3,900 65.99 +5
Functions 104.54 204.61 2,080 35.85 -0.96

Top API waits (after)

API request Max wait (ms)
account.name.update 466.45
functions.delete 458.5
functions.variables.update 452.89
tablesdb.rows.increment 352.72
functions.variables.create 338.94

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants