English

Developer tools · JSON formatter & validator

Fix a broken package.json before CI does: reading the error position

· Why it matters

json developer-workflow validation

Fix a broken package.json before CI does: reading the error position illustrated with JSON tokens and a precise validation boundary
Original ToolAcre vector illustration

A hand-edited package.json, composer.json or launch.json fails long after you saved it, usually in CI. This post shows how to validate before you commit and read the error position quickly.

Twelve minutes of pipeline to learn about one comma

Twelve minutes of pipeline to learn about one comma — a merge conflict resolved by hand, a green editor and a red build. The repository checkout can look normal because Git records bytes, not whether a manifest parses. CI then installs dependencies, reaches the damaged file and stops before tests provide any useful signal.

The tool checks strict JSON syntax only and accepts documents up to 8,000,000 JavaScript characters. package.json and composer.json are suitable strict examples. Files such as tsconfig.json may use a comment-tolerant parser, so rejecting their comments as JSON does not prove the owning tool will reject them. Validate against the grammar the consuming program actually declares.

Which JSON config files break most often

Which JSON config files break most often — package.json, composer.json, launch.json and lock files, and why tsconfig.json, which allows comments, needs separate care. Human-edited manifests tend to fail around dependency blocks, scripts and nested tool settings. Generated lock files fail differently: manual conflict resolution can damage delimiters or duplicate structural sections.

Do not assume every file with a JSON-like extension uses strict JSON. VS Code settings and TypeScript configuration commonly permit comments or trailing commas through specialized parsers, while package manifests generally do not. Validate a generated lock file with its package manager when possible, because valid syntax alone cannot restore hashes, ordering rules or internal consistency expected by that generator.

Why tools fail late — package managers and compilers parse on demand, so a syntax error surfaces at install or build time rather than on save

Why tools fail late — package managers and compilers parse on demand, so a syntax error surfaces at install or build time rather than on save. A text editor may color braces without running the authoritative parser, and a changed manifest may not be read during a narrow local task. CI starts from a clean environment and exercises setup paths that cached workstations skip.

The resulting delay includes queue time, checkout, dependency setup and unrelated preliminary jobs. Worse, the eventual message may name only an invalid package file while hiding the original line behind command output. A local parse immediately after editing collapses that feedback loop. It also separates a grammatical failure from later dependency-resolution or schema errors that require different investigation.

Reading the error position under pressure

Reading the error position under pressure — line and column, the previous token, and the three merge-conflict patterns that produce invalid JSON. The marked character is where continuation became impossible, not always where the mistake began. A closing quote may expose an earlier unescaped quote; a brace may reveal a missing comma immediately before the next property.

After merges, look for conflict markers left as plain text, duplicated member blocks joined without a comma, and delimiters deleted while choosing one side. Inspect the token before the reported location and count the surrounding container boundaries. Make one repair, rerun validation and preserve the original diff, because a parser usually reports only the first obstacle and a second independent conflict may remain farther down.

Worked example: a package.json after a bad merge

Worked example: a package.json after a bad merge — a duplicated dependencies block, a missing comma, the validator report and the fix. Imagine `"scripts":{"test":"vitest"}` followed immediately by `"dependencies":{"vite":"7.3.6"}`. The second property name is where the parser discovers that the object lacks a separator, although the corrective comma belongs after the scripts object.

Insert that comma and validate again before formatting. If the merge also produced two `dependencies` keys, strict parsing may still succeed because duplicate names are syntactically allowed, yet JavaScript parsing keeps only the later value. Compare both branches and combine the intended members rather than deleting a block mechanically. Syntax repair and semantic merge resolution are consecutive, distinct tasks.

Making validation a habit

Making validation a habit — paste before commit, or validate any JSON you edited outside an IDE, without needing an account or a plugin. The best trigger is behavioral: whenever conflict markers were resolved, a large block was moved or punctuation was typed manually, run the owning tool’s check or a strict parser before staging the file.

Repositories can automate the same rule with a pre-commit check and a CI job scoped to manifests, but automation should complement immediate feedback rather than become the first parser. Keep formatting separate from repair so the diff shows the meaningful character. For generated files, regenerate from the source manifest instead of normalizing hand-edited output, then let the generator prove its own invariants.

What this does not cover

What this does not cover — semantic mistakes such as a wrong version range or an unknown field, which valid JSON cannot protect you from. A package manifest can parse while naming a nonexistent script, putting a dependency in the wrong section or using a version expression that resolves unexpectedly. Duplicate keys can also pass grammar checks while silently replacing earlier values.

Use package-manager validation, schemas, install tests and review for those layers. This check also does not prove a lock file matches its manifest or that a launch configuration names an installed debugger. If the actual format is JSONC or another dialect, use its parser rather than removing supported syntax merely to satisfy strict JSON. Grammar is the earliest gate, not the complete configuration contract.

Takeaway: a syntax check costs seconds, a failed pipeline costs minutes

Takeaway: a syntax check costs seconds, a failed pipeline costs minutes — and the validator's precise report shortens the fix. Run it on the final edited bytes, start at the reported line and column, then inspect the preceding token for a missing separator or delimiter. Revalidate after every correction because later errors can be hidden initially.

Once strict syntax passes, return to the consumer: run the package manager, compiler or editor-specific validation that understands allowed fields and values. Keep repair diffs narrow, especially after merges, so reviewers can distinguish punctuation from dependency decisions. This sequence catches the cheapest failure locally and reserves expensive pipeline time for behavior that only the full environment can evaluate.