{"record":{"id":"1459ce266495ea8d","repo":"emberjs/ember.js","slug":"isconst-can-only-be-used-on-a-cache-once-getvalu","errorCode":null,"errorMessage":"isConst() can only be used on a cache once getValue() has been called at least once. Called with cache function:\\n\\n${String(cache[FN])}","messagePattern":"isConst\\(\\) can only be used on a cache once getValue\\(\\) has been called at least once\\. Called with cache function:\\\\n\\\\n(.+?)","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/@glimmer/validator/lib/tracking.ts","lineNumber":217,"sourceCode":"\nfunction assertCache<T>(\n  value: Cache<T> | InternalCache<T>,\n  fnName: string\n): asserts value is InternalCache<T> {\n  if (DEBUG && !(typeof value === 'object' && FN in value)) {\n    throw new Error(\n      `${fnName}() can only be used on an instance of a cache created with createCache(). Called with: ${String(\n        // eslint-disable-next-line @typescript-eslint/no-base-to-string -- @fixme\n        value\n      )}`\n    );\n  }\n}\n\n// replace this with `expect` when we can\nfunction assertTag(tag: Tag | undefined, cache: InternalCache): asserts tag is Tag {\n  if (DEBUG && tag === undefined) {\n    throw new Error(\n      `isConst() can only be used on a cache once getValue() has been called at least once. Called with cache function:\\n\\n${String(\n        cache[FN]\n      )}`\n    );\n  }\n}\n\n//////////\n\n// Legacy tracking APIs\n\n// track() shouldn't be necessary at all in the VM once the autotracking\n// refactors are merged, and we should generally be moving away from it. It may\n// be necessary in Ember for a while longer, but I think we'll be able to drop\n// it in favor of cache sooner rather than later.\nexport function track(block: () => void, debugLabel?: string | false): Tag {\n  beginTrackFrame(debugLabel);\n","sourceCodeStart":199,"sourceCodeEnd":235,"githubUrl":"https://github.com/emberjs/ember.js/blob/26f97246a8bf2e28edf26ac3093da2e86c04ffc5/packages/@glimmer/validator/lib/tracking.ts#L199-L235","documentation":"isConst() checks whether a cache's tag is still valid without invalidating it, but the tag only exists after getValue() has run at least once. In DEBUG builds, if the cache's internal tag is undefined, isConst throws telling you the cache function was never evaluated.","triggerScenarios":"Calling isConst(cache) before ever calling getValue(cache) on the same cache object.","commonSituations":"Conditional code paths where isConst is checked eagerly on first render; unit tests asserting constness without seeding the cache; moving isConst earlier during refactors.","solutions":["Call getValue(cache) at least once before calling isConst(cache)","Restructure so the value is consumed first, then constness checked","In tests, seed the cache with a getValue call before asserting isConst"],"exampleFix":"// before\nif (isConst(cache)) { hoist(); }\n// after\ngetValue(cache);\nif (isConst(cache)) { hoist(); }","handlingStrategy":"validation","validationCode":"let tag; const value = getValue(cache); // must run before isConst\nif (isConst(cache)) { hoist(value); }","typeGuard":null,"tryCatchPattern":"try { return isConst(cache); } catch (e) { if (String(e).includes('getValue()')) { getValue(cache); return isConst(cache); } throw e; }","preventionTips":["Never call isConst before at least one getValue on the same cache","Wrap cache creation + first read together in a helper","Cover cache constancy paths in tests with a seeded getValue"],"tags":["debug","validation","glimmer"],"backgroundTag":"invalid-cache-instance","analyzedSha":"26f97246a8bf2e28edf26ac3093da2e86c04ffc5","analyzedAt":"2026-09-01T05:01:28.182Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}