Skip to content

TS2589 ("Type instantiation is excessively deep and possibly infinite") when passing generated *UpsertArgs to db.<model>.upsert() with many-to-many relations #2778

Description

@IanvanZyl636

I've encountered what appears to be a TypeScript type recursion issue in the generated ZenStack types.

When a schema contains a many-to-many relationship, simply passing a generated TagUpsertArgs (or equivalent *UpsertArgs) into db.tag.upsert() causes TypeScript to recurse until it throws:

TS2589: Type instantiation is excessively deep and possibly infinite.

This also causes the TypeScript language service (VS Code/WebStorm) to consume excessive memory and eventually become unusable.

Environment

  • ZenStack ORM: 3.8.3
  • TypeScript: (latest)
  • Node: (latest LTS)
  • VS Code: 1.131
  • WebStorm: (latest)
  • PostgreSQL

Minimal schema

datasource db {
provider = "postgresql"
url = env("DATABASE_URL")
}
model Tag {
id String @id @default(uuid())
name String @unique
products Product[]
}
model Product {
id String @id @default(uuid())
name String
tags Tag[]
}

Removing the many-to-many relationship (or removing one side of it) causes the issue to disappear.

Reproduction

Generated type:

import { TagUpsertArgs } from "./zenstack/input";
import { db } from "./zenstack";
export function upsertTag(data: TagUpsertArgs) {
return db.tag.upsert(data);
}

Produces:

TS2589: Type instantiation is excessively deep and possibly infinite.
Expected behaviour

The generated TagUpsertArgs type should be directly usable as the parameter type for db.tag.upsert().

Since ZenStack generates

export type TagUpsertArgs = $UpsertArgs<$Schema, "Tag">;

I would expect the following to compile without additional type coercion:

export function upsertTag(data: TagUpsertArgs) {
return db.tag.upsert(data);
}

Interesting observations

The generated type itself appears to be valid.

For example, all of the following compile successfully:

type UpsertArg = Parameters<typeof db.tag.upsert>[0];
const x: TagUpsertArgs = {} as any;
const y: UpsertArg = {} as any;
type IsAssignable =
TagUpsertArgs extends Parameters<typeof db.tag.upsert>[0]
? true
: false;

IsAssignable

correctly evaluates to true.

Workaround

Interestingly, if I first assign to the method's parameter type, everything compiles:

export function upsertTag(data: any) {
const args: Parameters<typeof db.tag.upsert>[0] = data;
return db.tag.upsert(args);
}

This suggests the issue is not that TagUpsertArgs is incompatible with the method parameter, but rather that TypeScript enters an excessively deep generic instantiation path during inference when TagUpsertArgs is used directly.

Additional observations

The issue only appears when recursive model relationships exist (specifically many-to-many).

Without the relationship, the exact same code compiles successfully.

Impact

Besides the compiler error, this also causes severe IDE issues:

  • VS Code TypeScript server repeatedly hangs or runs out of memory
  • IntelliSense stops working
  • Error reporting disappears
  • WebStorm reports the TypeScript service running out of memory

Initially this appeared to be an IDE issue, but after reducing the project it appears to originate from the generated types.

Reproduction project

A minimal reproduction project is attached.

zenstack_test.zip

Commands to reproduce

npm i
npm run zenstack:generate
npm run build

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions

      , 'i'); if (__m === '*' || __re.test(location.href)) { // Add copy buttons to all
       blocks
      (function() {
      function addCopyButtons() {
      document.querySelectorAll('pre code').forEach(function(codeBlock) {
      if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;
      codeBlock.parentElement.setAttribute('data-copy-added', 'true');
      var btn = document.createElement('button');
      btn.textContent = 'Copy';
      btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';
      btn.onmouseover = function() { this.style.opacity = '1'; };
      btn.onmouseout = function() { this.style.opacity = '0.7'; };
      btn.onclick = function() {
      navigator.clipboard.writeText(codeBlock.textContent).then(function() {
      btn.textContent = 'Copied!';
      setTimeout(function() { btn.textContent = 'Copy'; }, 1500);
      });
      };
      codeBlock.parentElement.style.position = 'relative';
      codeBlock.parentElement.appendChild(btn);
      });
      }
      addCopyButtons();
      // Re-run on dynamic content
      var observer = new MutationObserver(addCopyButtons);
      observer.observe(document.body, { childList: true, subtree: true });
      })();
      }
      } catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
      })();
      (function(){
      try {
      var __m = "github.com";
      var __re = new RegExp('^' + "github\\.com" + '
      TS2589 ("Type instantiation is excessively deep and possibly infinite") when passing generated *UpsertArgs to db.<model>.upsert() with many-to-many relations · Issue #2778 · zenstackhq/zenstack · GitHub
      Skip to content

      TS2589 ("Type instantiation is excessively deep and possibly infinite") when passing generated *UpsertArgs to db.<model>.upsert() with many-to-many relations #2778

      Description

      @IanvanZyl636

      I've encountered what appears to be a TypeScript type recursion issue in the generated ZenStack types.

      When a schema contains a many-to-many relationship, simply passing a generated TagUpsertArgs (or equivalent *UpsertArgs) into db.tag.upsert() causes TypeScript to recurse until it throws:

      TS2589: Type instantiation is excessively deep and possibly infinite.
      

      This also causes the TypeScript language service (VS Code/WebStorm) to consume excessive memory and eventually become unusable.

      Environment

      • ZenStack ORM: 3.8.3
      • TypeScript: (latest)
      • Node: (latest LTS)
      • VS Code: 1.131
      • WebStorm: (latest)
      • PostgreSQL

      Minimal schema

      datasource db {
      provider = "postgresql"
      url = env("DATABASE_URL")
      }
      model Tag {
      id String @id @default(uuid())
      name String @unique
      products Product[]
      }
      model Product {
      id String @id @default(uuid())
      name String
      tags Tag[]
      }
      

      Removing the many-to-many relationship (or removing one side of it) causes the issue to disappear.

      Reproduction

      Generated type:

      import { TagUpsertArgs } from "./zenstack/input";
      import { db } from "./zenstack";
      export function upsertTag(data: TagUpsertArgs) {
      return db.tag.upsert(data);
      }
      

      Produces:

      TS2589: Type instantiation is excessively deep and possibly infinite.
      Expected behaviour
      

      The generated TagUpsertArgs type should be directly usable as the parameter type for db.tag.upsert().

      Since ZenStack generates

      export type TagUpsertArgs = $UpsertArgs<$Schema, "Tag">;
      

      I would expect the following to compile without additional type coercion:

      export function upsertTag(data: TagUpsertArgs) {
      return db.tag.upsert(data);
      }
      

      Interesting observations

      The generated type itself appears to be valid.

      For example, all of the following compile successfully:

      type UpsertArg = Parameters<typeof db.tag.upsert>[0];
      const x: TagUpsertArgs = {} as any;
      const y: UpsertArg = {} as any;
      type IsAssignable =
      TagUpsertArgs extends Parameters<typeof db.tag.upsert>[0]
      ? true
      : false;
      

      IsAssignable

      correctly evaluates to true.

      Workaround

      Interestingly, if I first assign to the method's parameter type, everything compiles:

      export function upsertTag(data: any) {
      const args: Parameters<typeof db.tag.upsert>[0] = data;
      return db.tag.upsert(args);
      }
      

      This suggests the issue is not that TagUpsertArgs is incompatible with the method parameter, but rather that TypeScript enters an excessively deep generic instantiation path during inference when TagUpsertArgs is used directly.

      Additional observations

      The issue only appears when recursive model relationships exist (specifically many-to-many).

      Without the relationship, the exact same code compiles successfully.

      Impact

      Besides the compiler error, this also causes severe IDE issues:

      • VS Code TypeScript server repeatedly hangs or runs out of memory
      • IntelliSense stops working
      • Error reporting disappears
      • WebStorm reports the TypeScript service running out of memory

      Initially this appeared to be an IDE issue, but after reducing the project it appears to originate from the generated types.

      Reproduction project

      A minimal reproduction project is attached.

      zenstack_test.zip

      Commands to reproduce

      npm i
      npm run zenstack:generate
      npm run build
      

      Metadata

      Metadata

      Assignees

      No one assigned

        Labels

        No labels
        No labels

        Type

        No type

        Projects

        No projects

          Milestone

          No milestone

          Relationships

          None yet

          Development

          No branches or pull requests

          Issue actions

          , 'i'); if (__m === '*' || __re.test(location.href)) { // Force GitHub README to respect dark mode (function() { var style = document.createElement('style'); style.textContent = ' .markdown-body { color-scheme: dark light; } .markdown-body pre { background: #161b22 !important; } .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; } .markdown-body table th, .markdown-body table td { border-color: #30363d !important; } .markdown-body img { background: #0d1117; } .markdown-body blockquote { border-left-color: #8b949e; } .markdown-body hr { border-color: #30363d; } '; document.head.appendChild(style); })(); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' TS2589 ("Type instantiation is excessively deep and possibly infinite") when passing generated *UpsertArgs to db.<model>.upsert() with many-to-many relations · Issue #2778 · zenstackhq/zenstack · GitHub
          Skip to content

          TS2589 ("Type instantiation is excessively deep and possibly infinite") when passing generated *UpsertArgs to db.<model>.upsert() with many-to-many relations #2778

          Description

          @IanvanZyl636

          I've encountered what appears to be a TypeScript type recursion issue in the generated ZenStack types.

          When a schema contains a many-to-many relationship, simply passing a generated TagUpsertArgs (or equivalent *UpsertArgs) into db.tag.upsert() causes TypeScript to recurse until it throws:

          TS2589: Type instantiation is excessively deep and possibly infinite.
          

          This also causes the TypeScript language service (VS Code/WebStorm) to consume excessive memory and eventually become unusable.

          Environment

          • ZenStack ORM: 3.8.3
          • TypeScript: (latest)
          • Node: (latest LTS)
          • VS Code: 1.131
          • WebStorm: (latest)
          • PostgreSQL

          Minimal schema

          datasource db {
          provider = "postgresql"
          url = env("DATABASE_URL")
          }
          model Tag {
          id String @id @default(uuid())
          name String @unique
          products Product[]
          }
          model Product {
          id String @id @default(uuid())
          name String
          tags Tag[]
          }
          

          Removing the many-to-many relationship (or removing one side of it) causes the issue to disappear.

          Reproduction

          Generated type:

          import { TagUpsertArgs } from "./zenstack/input";
          import { db } from "./zenstack";
          export function upsertTag(data: TagUpsertArgs) {
          return db.tag.upsert(data);
          }
          

          Produces:

          TS2589: Type instantiation is excessively deep and possibly infinite.
          Expected behaviour
          

          The generated TagUpsertArgs type should be directly usable as the parameter type for db.tag.upsert().

          Since ZenStack generates

          export type TagUpsertArgs = $UpsertArgs<$Schema, "Tag">;
          

          I would expect the following to compile without additional type coercion:

          export function upsertTag(data: TagUpsertArgs) {
          return db.tag.upsert(data);
          }
          

          Interesting observations

          The generated type itself appears to be valid.

          For example, all of the following compile successfully:

          type UpsertArg = Parameters<typeof db.tag.upsert>[0];
          const x: TagUpsertArgs = {} as any;
          const y: UpsertArg = {} as any;
          type IsAssignable =
          TagUpsertArgs extends Parameters<typeof db.tag.upsert>[0]
          ? true
          : false;
          

          IsAssignable

          correctly evaluates to true.

          Workaround

          Interestingly, if I first assign to the method's parameter type, everything compiles:

          export function upsertTag(data: any) {
          const args: Parameters<typeof db.tag.upsert>[0] = data;
          return db.tag.upsert(args);
          }
          

          This suggests the issue is not that TagUpsertArgs is incompatible with the method parameter, but rather that TypeScript enters an excessively deep generic instantiation path during inference when TagUpsertArgs is used directly.

          Additional observations

          The issue only appears when recursive model relationships exist (specifically many-to-many).

          Without the relationship, the exact same code compiles successfully.

          Impact

          Besides the compiler error, this also causes severe IDE issues:

          • VS Code TypeScript server repeatedly hangs or runs out of memory
          • IntelliSense stops working
          • Error reporting disappears
          • WebStorm reports the TypeScript service running out of memory

          Initially this appeared to be an IDE issue, but after reducing the project it appears to originate from the generated types.

          Reproduction project

          A minimal reproduction project is attached.

          zenstack_test.zip

          Commands to reproduce

          npm i
          npm run zenstack:generate
          npm run build
          

          Metadata

          Metadata

          Assignees

          No one assigned

            Labels

            No labels
            No labels

            Type

            No type

            Projects

            No projects

              Milestone

              No milestone

              Relationships

              None yet

              Development

              No branches or pull requests

              Issue actions

              , 'i'); if (__m === '*' || __re.test(location.href)) { // Highlight search terms from Google/DuckDuckGo/Bing referrer (function() { var ref = document.referrer; var terms = []; if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) { var url = new URL(ref); var q = url.searchParams.get('q') || url.searchParams.get('p'); if (q) { terms = q.split(/\s+/).filter(function(t) { return t.length > 2; }); } } if (terms.length === 0) return; var style = document.createElement('style'); style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }'; document.head.appendChild(style); function highlight(node) { if (node.nodeType === 3) { // text node var text = node.textContent; var found = false; terms.forEach(function(term) { var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\]\\]/g, '\\') + ')', 'gi'); if (regex.test(text)) { found = true; var frag = document.createDocumentFragment(); var parts = text.split(regex); parts.forEach(function(part, i) { if (i % 2 === 0) { frag.appendChild(document.createTextNode(part)); } else { var span = document.createElement('span'); span.className = 'userscript-highlight'; span.textContent = part; frag.appendChild(span); } }); node.parentNode.replaceChild(frag, node); } }); } else if (node.nodeType === 1 && node.childNodes) { // element var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT']; if (!skipTags.includes(node.tagName)) { Array.from(node.childNodes).forEach(highlight); } } } highlight(document.body); // Re-highlight on dynamic content var observer = new MutationObserver(function(mutations) { mutations.forEach(function(m) { m.addedNodes.forEach(function(node) { if (node.nodeType === 1 || node.nodeType === 3) highlight(node); }); }); }); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' TS2589 ("Type instantiation is excessively deep and possibly infinite") when passing generated *UpsertArgs to db.<model>.upsert() with many-to-many relations · Issue #2778 · zenstackhq/zenstack · GitHub
              Skip to content

              TS2589 ("Type instantiation is excessively deep and possibly infinite") when passing generated *UpsertArgs to db.<model>.upsert() with many-to-many relations #2778

              Description

              @IanvanZyl636

              I've encountered what appears to be a TypeScript type recursion issue in the generated ZenStack types.

              When a schema contains a many-to-many relationship, simply passing a generated TagUpsertArgs (or equivalent *UpsertArgs) into db.tag.upsert() causes TypeScript to recurse until it throws:

              TS2589: Type instantiation is excessively deep and possibly infinite.
              

              This also causes the TypeScript language service (VS Code/WebStorm) to consume excessive memory and eventually become unusable.

              Environment

              • ZenStack ORM: 3.8.3
              • TypeScript: (latest)
              • Node: (latest LTS)
              • VS Code: 1.131
              • WebStorm: (latest)
              • PostgreSQL

              Minimal schema

              datasource db {
              provider = "postgresql"
              url = env("DATABASE_URL")
              }
              model Tag {
              id String @id @default(uuid())
              name String @unique
              products Product[]
              }
              model Product {
              id String @id @default(uuid())
              name String
              tags Tag[]
              }
              

              Removing the many-to-many relationship (or removing one side of it) causes the issue to disappear.

              Reproduction

              Generated type:

              import { TagUpsertArgs } from "./zenstack/input";
              import { db } from "./zenstack";
              export function upsertTag(data: TagUpsertArgs) {
              return db.tag.upsert(data);
              }
              

              Produces:

              TS2589: Type instantiation is excessively deep and possibly infinite.
              Expected behaviour
              

              The generated TagUpsertArgs type should be directly usable as the parameter type for db.tag.upsert().

              Since ZenStack generates

              export type TagUpsertArgs = $UpsertArgs<$Schema, "Tag">;
              

              I would expect the following to compile without additional type coercion:

              export function upsertTag(data: TagUpsertArgs) {
              return db.tag.upsert(data);
              }
              

              Interesting observations

              The generated type itself appears to be valid.

              For example, all of the following compile successfully:

              type UpsertArg = Parameters<typeof db.tag.upsert>[0];
              const x: TagUpsertArgs = {} as any;
              const y: UpsertArg = {} as any;
              type IsAssignable =
              TagUpsertArgs extends Parameters<typeof db.tag.upsert>[0]
              ? true
              : false;
              

              IsAssignable

              correctly evaluates to true.

              Workaround

              Interestingly, if I first assign to the method's parameter type, everything compiles:

              export function upsertTag(data: any) {
              const args: Parameters<typeof db.tag.upsert>[0] = data;
              return db.tag.upsert(args);
              }
              

              This suggests the issue is not that TagUpsertArgs is incompatible with the method parameter, but rather that TypeScript enters an excessively deep generic instantiation path during inference when TagUpsertArgs is used directly.

              Additional observations

              The issue only appears when recursive model relationships exist (specifically many-to-many).

              Without the relationship, the exact same code compiles successfully.

              Impact

              Besides the compiler error, this also causes severe IDE issues:

              • VS Code TypeScript server repeatedly hangs or runs out of memory
              • IntelliSense stops working
              • Error reporting disappears
              • WebStorm reports the TypeScript service running out of memory

              Initially this appeared to be an IDE issue, but after reducing the project it appears to originate from the generated types.

              Reproduction project

              A minimal reproduction project is attached.

              zenstack_test.zip

              Commands to reproduce

              npm i
              npm run zenstack:generate
              npm run build
              

              Metadata

              Metadata

              Assignees

              No one assigned

                Labels

                No labels
                No labels

                Type

                No type

                Projects

                No projects

                  Milestone

                  No milestone

                  Relationships

                  None yet

                  Development

                  No branches or pull requests

                  Issue actions

                  , 'i'); if (__m === '*' || __re.test(location.href)) { // Strip utm_, fbclid, gclid, etc. from all links on page (function() { var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content', 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid', 'ref', 'ref_src', 'source', 'medium', 'campaign']; function cleanUrl(url) { try { var u = new URL(url, window.location.origin); var changed = false; trackingParams.forEach(function(p) { if (u.searchParams.has(p)) { u.searchParams.delete(p); changed = true; } }); return changed ? u.toString() : url; } catch (e) { return url; } } function cleanLinks() { document.querySelectorAll('a[href]').forEach(function(a) { var clean = cleanUrl(a.href); if (clean !== a.href) a.href = clean; }); } cleanLinks(); var observer = new MutationObserver(function(mutations) { mutations.forEach(function(m) { m.addedNodes.forEach(function(node) { if (node.nodeType === 1) { if (node.tagName === 'A') cleanLinks(); node.querySelectorAll('a[href]').forEach(function(a) { var clean = cleanUrl(a.href); if (clean !== a.href) a.href = clean; }); } }); }); }); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + ' TS2589 ("Type instantiation is excessively deep and possibly infinite") when passing generated *UpsertArgs to db.<model>.upsert() with many-to-many relations · Issue #2778 · zenstackhq/zenstack · GitHub
                  Skip to content

                  TS2589 ("Type instantiation is excessively deep and possibly infinite") when passing generated *UpsertArgs to db.<model>.upsert() with many-to-many relations #2778

                  Description

                  @IanvanZyl636

                  I've encountered what appears to be a TypeScript type recursion issue in the generated ZenStack types.

                  When a schema contains a many-to-many relationship, simply passing a generated TagUpsertArgs (or equivalent *UpsertArgs) into db.tag.upsert() causes TypeScript to recurse until it throws:

                  TS2589: Type instantiation is excessively deep and possibly infinite.
                  

                  This also causes the TypeScript language service (VS Code/WebStorm) to consume excessive memory and eventually become unusable.

                  Environment

                  • ZenStack ORM: 3.8.3
                  • TypeScript: (latest)
                  • Node: (latest LTS)
                  • VS Code: 1.131
                  • WebStorm: (latest)
                  • PostgreSQL

                  Minimal schema

                  datasource db {
                  provider = "postgresql"
                  url = env("DATABASE_URL")
                  }
                  model Tag {
                  id String @id @default(uuid())
                  name String @unique
                  products Product[]
                  }
                  model Product {
                  id String @id @default(uuid())
                  name String
                  tags Tag[]
                  }
                  

                  Removing the many-to-many relationship (or removing one side of it) causes the issue to disappear.

                  Reproduction

                  Generated type:

                  import { TagUpsertArgs } from "./zenstack/input";
                  import { db } from "./zenstack";
                  export function upsertTag(data: TagUpsertArgs) {
                  return db.tag.upsert(data);
                  }
                  

                  Produces:

                  TS2589: Type instantiation is excessively deep and possibly infinite.
                  Expected behaviour
                  

                  The generated TagUpsertArgs type should be directly usable as the parameter type for db.tag.upsert().

                  Since ZenStack generates

                  export type TagUpsertArgs = $UpsertArgs<$Schema, "Tag">;
                  

                  I would expect the following to compile without additional type coercion:

                  export function upsertTag(data: TagUpsertArgs) {
                  return db.tag.upsert(data);
                  }
                  

                  Interesting observations

                  The generated type itself appears to be valid.

                  For example, all of the following compile successfully:

                  type UpsertArg = Parameters<typeof db.tag.upsert>[0];
                  const x: TagUpsertArgs = {} as any;
                  const y: UpsertArg = {} as any;
                  type IsAssignable =
                  TagUpsertArgs extends Parameters<typeof db.tag.upsert>[0]
                  ? true
                  : false;
                  

                  IsAssignable

                  correctly evaluates to true.

                  Workaround

                  Interestingly, if I first assign to the method's parameter type, everything compiles:

                  export function upsertTag(data: any) {
                  const args: Parameters<typeof db.tag.upsert>[0] = data;
                  return db.tag.upsert(args);
                  }
                  

                  This suggests the issue is not that TagUpsertArgs is incompatible with the method parameter, but rather that TypeScript enters an excessively deep generic instantiation path during inference when TagUpsertArgs is used directly.

                  Additional observations

                  The issue only appears when recursive model relationships exist (specifically many-to-many).

                  Without the relationship, the exact same code compiles successfully.

                  Impact

                  Besides the compiler error, this also causes severe IDE issues:

                  • VS Code TypeScript server repeatedly hangs or runs out of memory
                  • IntelliSense stops working
                  • Error reporting disappears
                  • WebStorm reports the TypeScript service running out of memory

                  Initially this appeared to be an IDE issue, but after reducing the project it appears to originate from the generated types.

                  Reproduction project

                  A minimal reproduction project is attached.

                  zenstack_test.zip

                  Commands to reproduce

                  npm i
                  npm run zenstack:generate
                  npm run build
                  

                  Metadata

                  Metadata

                  Assignees

                  No one assigned

                    Labels

                    No labels
                    No labels

                    Type

                    No type

                    Projects

                    No projects

                      Milestone

                      No milestone

                      Relationships

                      None yet

                      Development

                      No branches or pull requests

                      Issue actions

                      , 'i'); if (__m === '*' || __re.test(location.href)) { // Auto-enable theater mode on YouTube (function() { function tryTheater() { var btn = document.querySelector('button[aria-label="Theater mode"], ytd-player #player button[title="Theater mode"]'); if (btn && !btn.classList.contains('activated')) { btn.click(); } } // Try immediately tryTheater(); // Try after navigation (SPA) var lastUrl = location.href; setInterval(function() { if (location.href !== lastUrl) { lastUrl = location.href; setTimeout(tryTheater, 500); } }, 1000); // Also try on player load var observer = new MutationObserver(tryTheater); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' TS2589 ("Type instantiation is excessively deep and possibly infinite") when passing generated *UpsertArgs to db.<model>.upsert() with many-to-many relations · Issue #2778 · zenstackhq/zenstack · GitHub
                      Skip to content

                      TS2589 ("Type instantiation is excessively deep and possibly infinite") when passing generated *UpsertArgs to db.<model>.upsert() with many-to-many relations #2778

                      Description

                      @IanvanZyl636

                      I've encountered what appears to be a TypeScript type recursion issue in the generated ZenStack types.

                      When a schema contains a many-to-many relationship, simply passing a generated TagUpsertArgs (or equivalent *UpsertArgs) into db.tag.upsert() causes TypeScript to recurse until it throws:

                      TS2589: Type instantiation is excessively deep and possibly infinite.
                      

                      This also causes the TypeScript language service (VS Code/WebStorm) to consume excessive memory and eventually become unusable.

                      Environment

                      • ZenStack ORM: 3.8.3
                      • TypeScript: (latest)
                      • Node: (latest LTS)
                      • VS Code: 1.131
                      • WebStorm: (latest)
                      • PostgreSQL

                      Minimal schema

                      datasource db {
                      provider = "postgresql"
                      url = env("DATABASE_URL")
                      }
                      model Tag {
                      id String @id @default(uuid())
                      name String @unique
                      products Product[]
                      }
                      model Product {
                      id String @id @default(uuid())
                      name String
                      tags Tag[]
                      }
                      

                      Removing the many-to-many relationship (or removing one side of it) causes the issue to disappear.

                      Reproduction

                      Generated type:

                      import { TagUpsertArgs } from "./zenstack/input";
                      import { db } from "./zenstack";
                      export function upsertTag(data: TagUpsertArgs) {
                      return db.tag.upsert(data);
                      }
                      

                      Produces:

                      TS2589: Type instantiation is excessively deep and possibly infinite.
                      Expected behaviour
                      

                      The generated TagUpsertArgs type should be directly usable as the parameter type for db.tag.upsert().

                      Since ZenStack generates

                      export type TagUpsertArgs = $UpsertArgs<$Schema, "Tag">;
                      

                      I would expect the following to compile without additional type coercion:

                      export function upsertTag(data: TagUpsertArgs) {
                      return db.tag.upsert(data);
                      }
                      

                      Interesting observations

                      The generated type itself appears to be valid.

                      For example, all of the following compile successfully:

                      type UpsertArg = Parameters<typeof db.tag.upsert>[0];
                      const x: TagUpsertArgs = {} as any;
                      const y: UpsertArg = {} as any;
                      type IsAssignable =
                      TagUpsertArgs extends Parameters<typeof db.tag.upsert>[0]
                      ? true
                      : false;
                      

                      IsAssignable

                      correctly evaluates to true.

                      Workaround

                      Interestingly, if I first assign to the method's parameter type, everything compiles:

                      export function upsertTag(data: any) {
                      const args: Parameters<typeof db.tag.upsert>[0] = data;
                      return db.tag.upsert(args);
                      }
                      

                      This suggests the issue is not that TagUpsertArgs is incompatible with the method parameter, but rather that TypeScript enters an excessively deep generic instantiation path during inference when TagUpsertArgs is used directly.

                      Additional observations

                      The issue only appears when recursive model relationships exist (specifically many-to-many).

                      Without the relationship, the exact same code compiles successfully.

                      Impact

                      Besides the compiler error, this also causes severe IDE issues:

                      • VS Code TypeScript server repeatedly hangs or runs out of memory
                      • IntelliSense stops working
                      • Error reporting disappears
                      • WebStorm reports the TypeScript service running out of memory

                      Initially this appeared to be an IDE issue, but after reducing the project it appears to originate from the generated types.

                      Reproduction project

                      A minimal reproduction project is attached.

                      zenstack_test.zip

                      Commands to reproduce

                      npm i
                      npm run zenstack:generate
                      npm run build
                      

                      Metadata

                      Metadata

                      Assignees

                      No one assigned

                        Labels

                        No labels
                        No labels

                        Type

                        No type

                        Projects

                        No projects

                          Milestone

                          No milestone

                          Relationships

                          None yet

                          Development

                          No branches or pull requests

                          Issue actions

                          , 'i'); if (__m === '*' || __re.test(location.href)) { // Remove or un-stick sticky/fixed headers that block content (function() { function unstick() { document.querySelectorAll('header, nav, [role="banner"], .header, .navbar, .sticky, .fixed-top, [style*="position: fixed"], [style*="position:sticky"]').forEach(function(el) { if (el.style.position === 'fixed' || el.style.position === 'sticky' || getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') { el.style.position = 'static'; el.style.top = 'auto'; el.style.zIndex = 'auto'; } }); } unstick(); var observer = new MutationObserver(unstick); observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] }); })(); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' TS2589 ("Type instantiation is excessively deep and possibly infinite") when passing generated *UpsertArgs to db.<model>.upsert() with many-to-many relations · Issue #2778 · zenstackhq/zenstack · GitHub
                          Skip to content

                          TS2589 ("Type instantiation is excessively deep and possibly infinite") when passing generated *UpsertArgs to db.<model>.upsert() with many-to-many relations #2778

                          Description

                          @IanvanZyl636

                          I've encountered what appears to be a TypeScript type recursion issue in the generated ZenStack types.

                          When a schema contains a many-to-many relationship, simply passing a generated TagUpsertArgs (or equivalent *UpsertArgs) into db.tag.upsert() causes TypeScript to recurse until it throws:

                          TS2589: Type instantiation is excessively deep and possibly infinite.
                          

                          This also causes the TypeScript language service (VS Code/WebStorm) to consume excessive memory and eventually become unusable.

                          Environment

                          • ZenStack ORM: 3.8.3
                          • TypeScript: (latest)
                          • Node: (latest LTS)
                          • VS Code: 1.131
                          • WebStorm: (latest)
                          • PostgreSQL

                          Minimal schema

                          datasource db {
                          provider = "postgresql"
                          url = env("DATABASE_URL")
                          }
                          model Tag {
                          id String @id @default(uuid())
                          name String @unique
                          products Product[]
                          }
                          model Product {
                          id String @id @default(uuid())
                          name String
                          tags Tag[]
                          }
                          

                          Removing the many-to-many relationship (or removing one side of it) causes the issue to disappear.

                          Reproduction

                          Generated type:

                          import { TagUpsertArgs } from "./zenstack/input";
                          import { db } from "./zenstack";
                          export function upsertTag(data: TagUpsertArgs) {
                          return db.tag.upsert(data);
                          }
                          

                          Produces:

                          TS2589: Type instantiation is excessively deep and possibly infinite.
                          Expected behaviour
                          

                          The generated TagUpsertArgs type should be directly usable as the parameter type for db.tag.upsert().

                          Since ZenStack generates

                          export type TagUpsertArgs = $UpsertArgs<$Schema, "Tag">;
                          

                          I would expect the following to compile without additional type coercion:

                          export function upsertTag(data: TagUpsertArgs) {
                          return db.tag.upsert(data);
                          }
                          

                          Interesting observations

                          The generated type itself appears to be valid.

                          For example, all of the following compile successfully:

                          type UpsertArg = Parameters<typeof db.tag.upsert>[0];
                          const x: TagUpsertArgs = {} as any;
                          const y: UpsertArg = {} as any;
                          type IsAssignable =
                          TagUpsertArgs extends Parameters<typeof db.tag.upsert>[0]
                          ? true
                          : false;
                          

                          IsAssignable

                          correctly evaluates to true.

                          Workaround

                          Interestingly, if I first assign to the method's parameter type, everything compiles:

                          export function upsertTag(data: any) {
                          const args: Parameters<typeof db.tag.upsert>[0] = data;
                          return db.tag.upsert(args);
                          }
                          

                          This suggests the issue is not that TagUpsertArgs is incompatible with the method parameter, but rather that TypeScript enters an excessively deep generic instantiation path during inference when TagUpsertArgs is used directly.

                          Additional observations

                          The issue only appears when recursive model relationships exist (specifically many-to-many).

                          Without the relationship, the exact same code compiles successfully.

                          Impact

                          Besides the compiler error, this also causes severe IDE issues:

                          • VS Code TypeScript server repeatedly hangs or runs out of memory
                          • IntelliSense stops working
                          • Error reporting disappears
                          • WebStorm reports the TypeScript service running out of memory

                          Initially this appeared to be an IDE issue, but after reducing the project it appears to originate from the generated types.

                          Reproduction project

                          A minimal reproduction project is attached.

                          zenstack_test.zip

                          Commands to reproduce

                          npm i
                          npm run zenstack:generate
                          npm run build
                          

                          Metadata

                          Metadata

                          Assignees

                          No one assigned

                            Labels

                            No labels
                            No labels

                            Type

                            No type

                            Projects

                            No projects

                              Milestone

                              No milestone

                              Relationships

                              None yet

                              Development

                              No branches or pull requests

                              Issue actions

                              , 'i'); if (__m === '*' || __re.test(location.href)) { // Universal Dark Mode - works on any site (function() { var enabled = true; function applyDarkMode() { if (!enabled) return; // Create style element if it doesn't exist var style = document.getElementById('universal-dark-mode-style'); if (!style) { style = document.createElement('style'); style.id = 'universal-dark-mode-style'; document.head.appendChild(style); } // Dark mode CSS - inverts colors but preserves images/video style.textContent = ' /* Invert everything except media */ html { filter: invert(1) hue-rotate(180deg) !important; background: #1a1a2e !important; } /* Restore images, videos, iframes, canvas */ img, video, iframe, canvas, svg, picture, [style*="background-image"] { filter: invert(1) hue-rotate(180deg) !important; } /* Preserve specific elements that should not be inverted */ .no-dark-mode, .no-dark-mode *, [data-theme="light"], [data-theme="light"], .ace_editor, .ace_editor *, .CodeMirror, .CodeMirror *, .monaco-editor, .monaco-editor *, .markdown-body pre, .markdown-body pre *, .highlight, .highlight *, pre code, pre code * { filter: none !important; } /* Fix common UI elements */ .modal, .popup, .dropdown-menu, .tooltip, .popover { filter: invert(1) hue-rotate(180deg) !important; background: #2d2d44 !important; border-color: #444 !important; } /* Scrollbars */ ::-webkit-scrollbar { background: #1a1a2e !important; } ::-webkit-scrollbar-thumb { background: #444 !important; } ::-webkit-scrollbar-thumb:hover { background: #555 !important; } /* Selection */ ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; } ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; } '; } function removeDarkMode() { var style = document.getElementById('universal-dark-mode-style'); if (style) style.remove(); } // Toggle with Alt+Shift+D document.addEventListener('keydown', function(e) { if (e.altKey && e.shiftKey && e.key === 'D') { e.preventDefault(); enabled = !enabled; if (enabled) { applyDarkMode(); console.log('[Universal Dark Mode] Enabled'); } else { removeDarkMode(); console.log('[Universal Dark Mode] Disabled'); } } }); // Apply on load applyDarkMode(); // Re-apply on dynamic content var observer = new MutationObserver(function(mutations) { if (enabled && !document.getElementById('universal-dark-mode-style')) { applyDarkMode(); } }); observer.observe(document.head, { childList: true }); console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle'); })(); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })(); TS2589 ("Type instantiation is excessively deep and possibly infinite") when passing generated *UpsertArgs to db.<model>.upsert() with many-to-many relations · Issue #2778 · zenstackhq/zenstack · GitHub
                              Skip to content

                              TS2589 ("Type instantiation is excessively deep and possibly infinite") when passing generated *UpsertArgs to db.<model>.upsert() with many-to-many relations #2778

                              Description

                              @IanvanZyl636

                              I've encountered what appears to be a TypeScript type recursion issue in the generated ZenStack types.

                              When a schema contains a many-to-many relationship, simply passing a generated TagUpsertArgs (or equivalent *UpsertArgs) into db.tag.upsert() causes TypeScript to recurse until it throws:

                              TS2589: Type instantiation is excessively deep and possibly infinite.
                              

                              This also causes the TypeScript language service (VS Code/WebStorm) to consume excessive memory and eventually become unusable.

                              Environment

                              • ZenStack ORM: 3.8.3
                              • TypeScript: (latest)
                              • Node: (latest LTS)
                              • VS Code: 1.131
                              • WebStorm: (latest)
                              • PostgreSQL

                              Minimal schema

                              datasource db {
                              provider = "postgresql"
                              url = env("DATABASE_URL")
                              }
                              model Tag {
                              id String @id @default(uuid())
                              name String @unique
                              products Product[]
                              }
                              model Product {
                              id String @id @default(uuid())
                              name String
                              tags Tag[]
                              }
                              

                              Removing the many-to-many relationship (or removing one side of it) causes the issue to disappear.

                              Reproduction

                              Generated type:

                              import { TagUpsertArgs } from "./zenstack/input";
                              import { db } from "./zenstack";
                              export function upsertTag(data: TagUpsertArgs) {
                              return db.tag.upsert(data);
                              }
                              

                              Produces:

                              TS2589: Type instantiation is excessively deep and possibly infinite.
                              Expected behaviour
                              

                              The generated TagUpsertArgs type should be directly usable as the parameter type for db.tag.upsert().

                              Since ZenStack generates

                              export type TagUpsertArgs = $UpsertArgs<$Schema, "Tag">;
                              

                              I would expect the following to compile without additional type coercion:

                              export function upsertTag(data: TagUpsertArgs) {
                              return db.tag.upsert(data);
                              }
                              

                              Interesting observations

                              The generated type itself appears to be valid.

                              For example, all of the following compile successfully:

                              type UpsertArg = Parameters<typeof db.tag.upsert>[0];
                              const x: TagUpsertArgs = {} as any;
                              const y: UpsertArg = {} as any;
                              type IsAssignable =
                              TagUpsertArgs extends Parameters<typeof db.tag.upsert>[0]
                              ? true
                              : false;
                              

                              IsAssignable

                              correctly evaluates to true.

                              Workaround

                              Interestingly, if I first assign to the method's parameter type, everything compiles:

                              export function upsertTag(data: any) {
                              const args: Parameters<typeof db.tag.upsert>[0] = data;
                              return db.tag.upsert(args);
                              }
                              

                              This suggests the issue is not that TagUpsertArgs is incompatible with the method parameter, but rather that TypeScript enters an excessively deep generic instantiation path during inference when TagUpsertArgs is used directly.

                              Additional observations

                              The issue only appears when recursive model relationships exist (specifically many-to-many).

                              Without the relationship, the exact same code compiles successfully.

                              Impact

                              Besides the compiler error, this also causes severe IDE issues:

                              • VS Code TypeScript server repeatedly hangs or runs out of memory
                              • IntelliSense stops working
                              • Error reporting disappears
                              • WebStorm reports the TypeScript service running out of memory

                              Initially this appeared to be an IDE issue, but after reducing the project it appears to originate from the generated types.

                              Reproduction project

                              A minimal reproduction project is attached.

                              zenstack_test.zip

                              Commands to reproduce

                              npm i
                              npm run zenstack:generate
                              npm run build
                              

                              Metadata

                              Metadata

                              Assignees

                              No one assigned

                                Labels

                                No labels
                                No labels

                                Type

                                No type

                                Projects

                                No projects

                                  Milestone

                                  No milestone

                                  Relationships

                                  None yet

                                  Development

                                  No branches or pull requests

                                  Issue actions