Skip to content

Conversation

@mjheilmann
Copy link
Collaborator

@mjheilmann mjheilmann commented Nov 29, 2025

This is an attempt to resolve the circular recursion case, in this PR:

  1. Rework the state to store the descriptor once, so symbols reference a filename instead of holding a duplicate descriptor
  2. Some state simplification, making some operations stricter
  3. Add a function that shrinks the state by combining cycles

When files participate in a cycle, causing the reflection tree to instead be a graph, we combine those participating file descriptors into a single descriptor.

  • minimal change from each-module-as-a-file
  • clients should now resolve schemas that contain cycles

@mjheilmann mjheilmann force-pushed the feature/cleanup_and_recursion branch from 4a2adc2 to 8333e21 Compare December 5, 2025 03:00
@aj-foster
Copy link

aj-foster commented Dec 17, 2025

Hi there 👋🏼

Thank you for working on this. I ran a few tests using this branch, and unfortunately the problem persists. Going to try and share as much information as possible, progressively, as time allows me to investigate further.

Current knowledge: we see infinite recursion in trace_message_refs/3, prior to the code modified in this PR. Still digging, as time allows, to figure out why.

Edit: It looks like the smallest reproducible test case might be any message that references google.protobuf.Struct. This message type is indirectly self-referential.

Edit 2: It's possible that the solution is related to adding a conditional based on State.has_symbol?/2 in the reduce call within trace_message_fields/4:

    |> Enum.reduce(state, fn %{mod: mod, symbol: symbol}, state ->
      symbol = Util.trim_symbol(symbol)

+     if State.has_symbol?(state, symbol) do
+       state
+     else
        response =
          if symbol in nested_types do
            build_response(parent_symbol, module)
          else
            build_response(symbol, mod)
          end

        state
        |> Extensions.add_extensions(symbol, mod)
        |> State.add_symbols(%{symbol => response})
        |> State.add_files(%{(symbol <> ".proto") => response})
        |> trace_message_refs(symbol, mod)
+     end
    end)

Unfortunately, while this addition avoids infinite recursion in my test cases, we get a different error (that may be completely unrelated, because it happens in this branch and on the latest release).

Edit 3: I see now that #59 is a better version of this suggestion.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants