Description
ConfigItem.earlyResolve() can cause a stack overflow (RangeError: Maximum call stack size exceeded) when the @currentEnv env flag item — or any item resolved early via @import enabled — has circular dependencies.
Root cause
earlyResolve() (packages/varlock/src/env-graph/lib/config-item.ts:272) recursively resolves dependency items without any termination guards:
- No idempotency check — unlike
resolve() (which checks this.isResolved at line 468), earlyResolve() will re-enter items that have already been resolved, causing redundant work on diamond dependencies.
- No cycle detection —
earlyResolve() runs during DataSource.finishInit(), which happens before EnvGraph.finishLoad() where findGraphCycles() is called (line 256). The normal cycle detection safety net does not exist yet at this point in the loading lifecycle.
If a circular dependency exists among items that participate in early resolution, the recursion has no termination condition and the process crashes.
Reproduction
# .env.schema
# @currentEnv=$APP_ENV
# ---
APP_ENV=$OTHER
OTHER=$APP_ENV
Running varlock run (or any command that loads this schema) crashes with RangeError: Maximum call stack size exceeded instead of reporting a schema error.
A self-referencing env flag (APP_ENV=$APP_ENV) also triggers the same crash.
Expected behavior
Circular dependencies in early-resolved items should produce a clear SchemaError / loading error, consistent with how cycles are reported during normal finishLoad() processing via findGraphCycles().
Affected code
packages/varlock/src/env-graph/lib/config-item.ts — earlyResolve() method (line 272)
packages/varlock/src/env-graph/lib/data-source.ts — call sites at lines 149, 293, 704
Description
ConfigItem.earlyResolve()can cause a stack overflow (RangeError: Maximum call stack size exceeded) when the@currentEnvenv flag item — or any item resolved early via@import enabled— has circular dependencies.Root cause
earlyResolve()(packages/varlock/src/env-graph/lib/config-item.ts:272) recursively resolves dependency items without any termination guards:resolve()(which checksthis.isResolvedat line 468),earlyResolve()will re-enter items that have already been resolved, causing redundant work on diamond dependencies.earlyResolve()runs duringDataSource.finishInit(), which happens beforeEnvGraph.finishLoad()wherefindGraphCycles()is called (line 256). The normal cycle detection safety net does not exist yet at this point in the loading lifecycle.If a circular dependency exists among items that participate in early resolution, the recursion has no termination condition and the process crashes.
Reproduction
Running
varlock run(or any command that loads this schema) crashes withRangeError: Maximum call stack size exceededinstead of reporting a schema error.A self-referencing env flag (
APP_ENV=$APP_ENV) also triggers the same crash.Expected behavior
Circular dependencies in early-resolved items should produce a clear
SchemaError/ loading error, consistent with how cycles are reported during normalfinishLoad()processing viafindGraphCycles().Affected code
packages/varlock/src/env-graph/lib/config-item.ts—earlyResolve()method (line 272)packages/varlock/src/env-graph/lib/data-source.ts— call sites at lines 149, 293, 704