nitro icon indicating copy to clipboard operation
nitro copied to clipboard

Nitrogen crashes with self-referential struct types (Maximum call stack size exceeded)

Open puckey opened this issue 4 weeks ago • 3 comments

What happened?

When defining a self-referential struct type, Nitrogen crashes with RangeError: Maximum call stack size exceeded.

See https://github.com/mrousavy/nitro/pull/1069

Nitrogen CLI logs (with --logLevel="debug")

$ npx nitrogen --logLevel="debug"

🔧  Loading nitro.json config...
🚀  Nitrogen 0.31.10 runs at ~/rg/_libraries/nitro/packages/react-native-nitro-test
    🔍  Nitrogen found 1 spec in ./src/specs
⏳  Parsing Cyclic.nitro.ts...
    ⚙️   Generating specs for HybridObject "Cyclic"...
        ❌  Failed to generate spec for Cyclic! RangeError: Maximum call stack size exceeded
    ❌  No specs found in Cyclic.nitro.ts!
⛓️   Setting up build configs for autolinking...
    Creating autolinking build setup for ios...
          Ruby: Creating NitroTest+autolinking.rb...
          C++: Creating NitroTest-Swift-Cxx-Bridge.hpp...
          C++: Creating NitroTest-Swift-Cxx-Bridge.cpp...
          C++: Creating NitroTest-Swift-Cxx-Umbrella.hpp...
          Objective-c++: Creating NitroTestAutolinking.mm...
          Swift: Creating NitroTestAutolinking.swift...
🎉  Generated 0/1 HybridObjects in 0.7s!
💡  Your code is in ./nitrogen/generated

Nitro Specs (.nitro.ts)

import type { HybridObject } from 'react-native-nitro-modules'

export interface Node {
  node?: Node
}

export interface Cyclic
  extends HybridObject<{ ios: 'swift'; android: 'kotlin' }> {
  node?: Node
}

Nitro Modules Version

0.31.10

Nitrogen Version

0.31.10

Operating system

MacOS

Additional information

puckey avatar Dec 01 '25 10:12 puckey

JFYI; this will not be supported. A struct cannot reference itself cyclically, not in C++, not in Swift. Unless you make it a pointer/heap-allocated, but I don't think we should do that.

I should throw a better error tho :)

mrousavy avatar Dec 01 '25 12:12 mrousavy

Thanks for the explanation! Updated the PR with a more helpful error message that shows examples of both direct and indirect cyclic references, plus a link to some added docs to the struct section: https://github.com/mrousavy/nitro/pull/1071

puckey avatar Dec 01 '25 13:12 puckey

Hmm actually there are still stack overflow issues happening with valid non-cyclic patterns like structs containing callbacks that reference the same struct type:

  export interface RequestConfig {
    transform?: (request: RequestConfig) => Promise<RequestConfig>
  }

#1072 adds a failing test case for this

puckey avatar Dec 01 '25 15:12 puckey

I've opened a (Claude Code assisted) PR to address this: #1074

The fix handles cyclic struct references by:

  1. Detecting direct/indirect recursive structs (A→A or A→B→A) and throwing a clear error
  2. Supporting structs with callbacks that reference the same struct type (like the transform?: (config: MyStruct) => Promise<MyStruct> example)
  3. Generating separate .hpp/.cpp files for types with cyclic dependencies to avoid circular includes in the JNI headers

puckey avatar Dec 02 '25 13:12 puckey