How to fix malformed json lines in log files
- Step 1Find the failing log line — From your aggregator's dead-letter queue or a
grepover the raw log, isolate the one line that failed to parse. The fixer works on one event at a time, so copy a single line, not the whole file. - Step 2Paste the single line — Paste just that one JSON object into the input. If you paste several lines, the tool will treat them as one document and try to comma-join them — which is not what you want for NDJSON (see the edge cases).
- Step 3Pick an indent and click Fix JSON — Choose 2 or 4 spaces. The tool tries
JSON.parsefirst; if it throws, the five repair passes run and parsing is retried. For a dense log line, the re-indented output is far easier to read. - Step 4Read the Fixes applied list —
Removed trailing commas,Replaced single quotes with double quotes,Added quotes to unquoted object keys, orReplaced undefined with nulltell you exactly what your logger emitted wrong — which is the bug to fix upstream. - Step 5Check the banner before reprocessing — Green means the event is recoverable: copy it back into your pipeline or a fixtures file. Yellow means the breakage is a logger-side problem this tool can't fix — an unescaped newline in a stack trace, or a truncated record.
- Step 6Fix the root cause at the logger — The real fix lives in the logging library: escape newlines in string values, ensure objects are stringified once, and never log raw
undefined. The fixer recovers stranded events; the logger config prevents the next ones.
Log-line problems: fixable here vs fix at the logger
What this single-document fixer repairs in one log line, and what is a logging-library problem it cannot solve.
| Log-line problem | Fixable here? | Where the real fix lives |
|---|---|---|
| Trailing comma in the event object | Yes | n/a |
| Single-quoted keys/values from a custom formatter | Yes | n/a |
Unquoted keys (level: not "level":) | Yes | Custom formatter should emit JSON |
Literal undefined field value | Yes (→ null) | Logger should omit the key or log null |
| Unescaped newline in a stack-trace string | No | Escape \n in string values at the logger |
| Truncated line (buffer flush / process kill) | No | Increase buffer / flush on shutdown; line is lost |
Non-JSON prefix (2026-06-12 INFO {...}) | No | Strip the prefix before parse; configure JSON-only output |
| Whole multi-line log file pasted at once | No (joins lines wrongly) | Repair one line at a time |
NDJSON behavior you must know
How this fixer treats newline-delimited input. Critical for log work.
| You paste | What the tool does | Result |
|---|---|---|
| One broken JSON object | Runs the five passes, re-parses | Repaired event (if fixable) |
| Two objects on separate lines | Inserts a comma between } and the next { | A 2-element fragment that is NOT wrapped in [ ] — still invalid |
| A full NDJSON file | Treats it as one document | Comma-joined soup, reported invalid — don't do this |
| A valid single line | Re-indents only | No fixes needed, readable output |
Cookbook
Single-line log events, the fix applied, and the banner. Process one event at a time. PII anonymised.
One Pino line with a custom-formatter trailing comma
ExampleA redaction plugin re-serialized the event and left a trailing comma. The line was quarantined; the fixer recovers it.
Failing log line:
{"level":30,"msg":"request","path":"/api/orders",}
Fixes applied (1):
✓ Removed trailing commas
Banner: Fixed & valid JSON
Readable output (indent 2):
{
"level": 30,
"msg": "request",
"path": "/api/orders"
}Custom formatter emitted a JS object literal
ExampleA home-grown formatter logged unquoted keys and single quotes. Two passes recover the event and pinpoint the formatter bug.
Failing log line:
{ level: 'error', msg: 'db timeout', svc: 'checkout' }
Fixes applied (2):
✓ Replaced single quotes with double quotes
✓ Added quotes to unquoted object keys
Banner: Fixed & valid JSON
Root cause: formatter emits a JS literal, not JSON — fix the
formatter to JSON.stringify the event.undefined field from a JS logger
ExampleA merged context object carried an undefined. The fixer maps the value to null; the pass is string-aware, so a msg or any other string field containing the word 'undefined' is left untouched.
Failing log line:
{ "reqId": "abc", "userId": undefined, "msg": "hit" }
Fixes applied (1):
✓ Replaced undefined with null
Banner: Fixed & valid JSON
Logger fix: don't merge undefined values into the log context.Multi-line stack trace — NOT fixable here
ExampleAn exception was logged with a real newline inside the message string. The fixer can't escape it, and pasting the multi-line blob just confuses the single-document parser.
Failing log line (newline inside the string):
{"level":50,"err":"Error: boom
at handler (app.js:12)"}
Fixes applied (0)
Banner: Partially fixed — output may still have issues
Real fix at the logger: serialize the error so newlines are
escaped — "Error: boom\n at handler (app.js:12)"Don't paste the whole NDJSON file
ExamplePasting several lines makes the tool comma-join the objects without wrapping them in an array — still invalid. Process one line at a time instead.
Pasted (3 NDJSON lines):
{"id":1}
{"id":2}
{"id":3}
Fixes applied (1):
✓ Added missing commas between elements
Output:
{"id":1},
{"id":2},
{"id":3}
Banner: Partially fixed — NOT wrapped in [ ], so still invalid.
Correct approach: fix line 1, then line 2, then line 3.Errors and edge cases
Real errors and silent failures sourced from each platform's own documentation. Match the wording to the row, fix what the row says to fix.
Whole NDJSON file pasted at once
InvalidThe fixer is single-document. Pasted multi-line NDJSON gets comma-joined between } and the next { but never wrapped in [ ], so the result still fails JSON.parse. Repair one line at a time, or use a real NDJSON-aware step in your pipeline. This is the most common misuse for logs.
Unescaped newline inside a string value
FailA multi-line stack trace logged without escaping its newlines breaks JSON line parsing. The fixer has no newline-escaping pass; the line stays invalid. The only correct fix is at the logger — serialize errors so \n is escaped. Pre-joining lines with a regex before parsing is a fragile stopgap.
Truncated log line
FailA process killed mid-write or a buffer flush boundary leaves a line cut off ({"level":30,"ms). The fixer can't reconstruct missing bytes or add closing brackets — it reports the fragment invalid. The event is lost; prevent recurrence with proper flush-on-shutdown in the logger.
Non-JSON prefix on the line
InvalidLines like 2026-06-12T10:00:00 INFO {"msg":"hi"} mix a text prefix with JSON. The fixer treats the whole thing as one document and fails. Strip the prefix first (or configure JSON-only output), then fix the remaining object.
undefined inside a log message string is preserved
By designThe undefined pass is string-aware: it tracks string state while walking the line, so a msg like "value is undefined" is left exactly as-is. Only a bare undefined field value is rewritten to null. Your log text is never altered, so no review of string fields containing the word undefined is needed after fixing a line.
Apostrophe inside a single-quoted value
RejectA formatter that wrote 'can't connect' defeats the value-quote pass ('[^']*' stops at the inner apostrophe). The output is broken. Fix the formatter to use double quotes; correct the stranded line by hand.
Valid single line pasted
ExpectedA correctly-formatted log line parses on first try — no passes run, No fixes needed, and you get a nicely indented, human-readable version of a dense one-liner. Handy purely as a log pretty-printer while debugging.
Line longer than 2 MB on free tier
BlockedA single log line over 2 MB (huge embedded payload or base64 blob) is blocked on free tier. That usually signals a logging anti-pattern — don't log large blobs. Pro raises the file ceiling to 100 MB.
Duplicate keys in a log event
By designIf a formatter emitted the same key twice ({"t":1,"t":2}), JSON.parse keeps the last value silently and the fixer reports the line valid. It does not warn about duplicates. Audit your formatter if a field's value looks wrong after a fix.
Frequently asked questions
Can this repair my whole NDJSON log file at once?
No. It treats whatever you paste as a single JSON document, not a stream of independent lines. Pasting a full NDJSON file makes it comma-join the objects without wrapping them in an array, which still fails to parse. Repair one line at a time, or handle NDJSON in your pipeline.
What is NDJSON and why do loggers use it?
NDJSON (newline-delimited JSON) puts one complete JSON object per line. Each log event is self-contained, so a pipeline can read and parse events one at a time without loading the whole file. Pino, Bunyan, and Winston's JSON format all emit NDJSON. This tool fixes individual lines, not the stream.
Does it escape newlines in multi-line stack traces?
No — there's no newline-escaping pass. A stack trace logged with literal newlines inside the string breaks parsing and stays broken here. The correct fix is at the logger: serialize errors so \n is escaped before the line is written.
Can it recover a truncated log line?
No. If a process was killed mid-write or a buffer boundary cut the line, bytes are missing and the fixer can't reconstruct them or add closing brackets. It reports the fragment invalid. Prevent it with flush-on-shutdown in your logging setup.
Which log-line errors can it actually fix?
The same five it fixes everywhere: trailing commas, single-quoted keys/values, unquoted keys, the literal undefined (→ null), and a missing comma between two }/{ on separate lines. In practice the first four are what you hit with a misbehaving custom log formatter.
Will it change a word inside my log message?
No. The undefined → null pass is string-aware: it tracks string state as it walks the line, so the word undefined inside a msg (or any string field) is preserved. Only a bare undefined field VALUE becomes null. Your log text is left intact.
How do I strip the timestamp prefix some loggers add?
This tool won't — it treats 2026-06-12 INFO {...} as one document and fails. Remove the prefix first (a quick regex or your editor's column select), then paste just the {...} object. Better, configure the logger to emit pure JSON lines with no leading text.
Once a line is valid, can I turn a batch of events into a table?
Yes. Fix each line to valid JSON, collect them into an array, and convert with json-to-csv for a spreadsheet, or flatten nested event objects into dot-notation columns first. To pull a single field out of many events, the JSON path extractor supports ..key recursive descent and filter expressions.
Is my log data uploaded?
No. Lines are read and fixed entirely in your browser. Log events often contain user IDs, request paths, and tokens, and none of it reaches JAD Apps servers. A signed-in run records only an anonymous counter with no content.
Does it warn about duplicate keys in an event?
No. If a formatter emitted a key twice, JSON.parse silently keeps the last value and the line is reported valid. The fixer has no duplicate-key detection. If a field looks wrong after fixing, audit the formatter that produced the line.
Can I use the output as a test fixture for my log parser?
Yes — fixing a real quarantined line to valid JSON gives you an authentic fixture to test your parser's handling of that event shape. Save the green-banner output and feed it to your parser's test suite.
What's the size limit per line?
2 MB on free tier, 100 MB on Pro. A single log line approaching 2 MB almost always means something large (a blob or full request body) is being logged that shouldn't be — fix the logging, not the size limit.
Privacy first
Conversion runs locally in your browser. No file is uploaded — only metadata counters are saved for signed-in dashboard stats.