Structured, coded errors and warnings in json-full output - #958
Structured, coded errors and warnings in json-full output#958theoephraim wants to merge 1 commit into
Conversation
Errors in the serialized graph were free-text strings, so anything consuming them programmatically had to regex English prose to work out what went wrong. They are now objects with a stable `code`, set explicitly per VarlockError subclass so renaming a class cannot silently change a published contract. Warnings are reported for the first time, under a separate `warnings` key with the same structure. Keeping them out of `errors` matters because the presence of `errors` means the load failed, and both our runtime and the cloudflare integration test it for truthiness. An empty graph is now an error in the output rather than a silently clean load. A .env.schema is still optional (plain .env files are a valid project); what fails is finding no env files at all (`no_env_files`) or files that define no items (`no_config_items`). json-full previously exited 0 for both, so a consumer pointed at a directory with no varlock project read it as success. The predicate lives on the graph now, shared with the CLI check so the two cannot drift on what counts as unusable. Decrypt failures carry the native encryption helper's own error code through instead of collapsing into a generic `resolution_failed`, falling back to `decrypt_failed`.
|
The changes in this PR will be included in the next version bump.
|
📦 Bundle size
dist/ only; native binaries are versioned separately and not counted here. |
Deploying with
|
| Status | Name | Latest Commit | Preview URL | Updated (UTC) |
|---|---|---|---|---|
| ✅ Deployment successful! View logs |
varlock-website | 11b937d | Commit Preview URL Branch Preview URL |
Jul 29 2026, 06:37 AM |
There was a problem hiding this comment.
Important
Two graph states still produce incomplete or incorrect structured diagnostics and should be covered before merging.
Reviewed changes: This PR gives json-full diagnostics stable codes and separates warnings from load-blocking errors while aligning empty-graph exit behavior.
- Structure serialized diagnostics:
errorsandwarningsnow contain coded objects grouped by root or config item. - Align empty-graph failures: shared graph logic emits
no_env_filesorno_config_itemsand makesjson-fullexit non-zero. - Preserve decrypt failure codes: local-encryption daemon codes flow through
ResolutionError, withdecrypt_failedas the fallback. - Document and test the contract: reference docs and focused tests cover the new shape, warning partitioning, and common failure codes.
azure/gpt-5.6-sol | 𝕏
| * two can't drift on what counts as an unusable graph. | ||
| */ | ||
| getEmptyGraphError(opts?: { hasOtherRootErrors?: boolean }): VarlockError | undefined { | ||
| if (Object.keys(this.configSchema).length > 0) return undefined; |
There was a problem hiding this comment.
configSchema can be non-empty even when the files define no application items because a reference such as @currentEnv=$VARLOCK_ENV auto-registers the builtin VARLOCK_ENV item. I reproduced that builtin-only graph returning no errors, so json-full exits zero despite the documented no_config_items rule; base this decision on non-builtin or file-defined items and add this case to the empty-graph tests.
| for (const source of this.sortedDataSources) { | ||
| for (const err of source.errors.filter((e) => !e.isWarning)) { | ||
| rootErrors.push(`${source.label}: ${err.message}`); | ||
| for (const err of source.errors) { |
There was a problem hiding this comment.
source.errors, while plugins keep a separate plugin.warnings collection that pretty displays through showPluginWarnings. As a result, warnings such as the standard-variable wiring warning remain invisible in json-full; include plugin warnings in warnings.root with an appropriate source and cover that path.
commit: |



--format json-fullreported errors as free-text strings, so anything consuming them programmatically had to regex English prose to work out what went wrong. They are now objects with a stablecode:Codes are set explicitly per
VarlockErrorsubclass rather than derived from the class name, so renaming a class can't silently change a published contract. Each key maps to an array, since an item can hit several problems at once (config-item.tscomposes schema, resolver, decorator, resolution, coercion and validation errors) and the old code joined them with'; '.Warnings
Reported for the first time, under a separate
warningskey. A warning-only item was previously invisible to any programmatic consumer even thoughprettyprinted it.They are deliberately not folded into
errorswithseveritydoing the work. The presence oferrorshas to keep meaning "the load failed" - runtime/env.ts:390 and cloudflare/src/index.ts:202 both test it for truthiness, and unifying would silently turn a warning-only load into a failure. There's a test pinning that.Empty graph is now an error
A
.env.schemais still optional; a project of plain.envfiles loads fine. What fails is finding no env files at all (no_env_files) or files that define no items (no_config_items).json-fullpreviously exited 0 for both, emittingconfig: {}anderrors: null, so a tool pointed at a directory with no varlock project read it as success and silently contributed nothing. Plain--format jsonexited 1 for the same case, so the two formats disagreed. The predicate now lives on the graph (getEmptyGraphError) and is shared with the CLI'scheckForNoEnvFiles, which had been about to drift: the CLI suppressed the "no items" message only forParseError, while any root error should suppress it.Decrypt failures
builtin-resolver.tsflattened every decrypt failure into a genericresolution_failed. It now passes the native encryption helper's own error code through, falling back todecrypt_failed. That also means future helper-side codes surface end to end without further plumbing.Breaking
The
errorsshape changes from strings to objects. Markedminor: no in-repo consumer reads past truthiness and the shape was undocumented until this PR. Bump to major instead if published JSON output should be treated as a stability boundary.SerializedEnvGraphErrorsis renamed toSerializedEnvGraphDiagnosticswith the old name kept as a deprecated alias.Anything that iterates the serialized graph looking for problems will now also see warnings it didn't before. Anything checking
errorsalone is unaffected.Testing
11 new tests. Verified end to end against the built CLI:
jsonjson-fullno_env_filesno_config_items.envonly, has varsparse_errorempty_required_valuecoercion_faileddecrypt_failedschema_errorExit codes now agree between the two formats, and
prettyoutput is unchanged.