Skip to content

Fix StackOverflowError from self-referential supertype in Python type mapping#7240

Merged
knutwannheden merged 1 commit intomainfrom
fix-stackoverflowerror-in-typeutils.isassignableto
Apr 2, 2026
Merged

Fix StackOverflowError from self-referential supertype in Python type mapping#7240
knutwannheden merged 1 commit intomainfrom
fix-stackoverflowerror-in-typeutils.isassignableto

Conversation

@knutwannheden
Copy link
Copy Markdown
Contributor

@knutwannheden knutwannheden commented Apr 2, 2026

Motivation

Flagship recipe run alerts on app.moderne.io revealed ~7,400 per-file StackOverflowErrors in TypeUtils.isAssignableTo(), all from 3 variants of importlib_metadata/__init__.py in Netflix/metaflow. The root cause is the class Pair(namedtuple('Pair', ...)) pattern in importlib_metadata._collections.

namedtuple('Pair', ...) generates a class also named Pair, so ty-types emits two classLiteral descriptors with the same FQN but different type_ids. The classLiteral handler used _create_class_type() which deduplicates by FQN, collapsing both into the same JavaType.Class object. When the outer class sets its supertype to the inner namedtuple type, it ends up pointing to itself — Pair._supertype = Pair.

Summary

  • Stop using FQN-based _create_class_type() in the classLiteral handler
  • Create a fresh JavaType.Class per classLiteral type_id instead — ty-types type_ids are the correct source of truth for type identity
  • The _type_id_cache in _resolve_type() already handles deduplication by type_id

Test plan

  • test_namedtuple_subclass_no_self_supertype: constructs the exact namedtuple pattern (two classLiterals, same FQN, one is supertype of the other), verifies no self-referential supertype
  • Verified against actual metaflow/_vendor/importlib_metadata/__init__.pyPair now has two distinct JavaType.Class objects, no cycles
  • Full test_type_attribution.py passes (101 tests, no regressions)

…pattern

The pattern `class Pair(namedtuple('Pair', ...))` causes ty-types to emit
two classLiteral descriptors with the same FQN but different type_ids. The
classLiteral handler used _create_class_type() which deduplicates by FQN,
collapsing both into the same JavaType.Class object. When the outer class
sets its supertype to the inner namedtuple type, it ends up pointing to
itself — a self-loop that causes StackOverflowError in Java's
TypeUtils.isAssignableTo().

Fix by creating a fresh JavaType.Class per classLiteral type_id instead of
deduplicating by FQN. The _type_id_cache in _resolve_type() already handles
deduplication by type_id, and ty-types type_ids are the correct source of
truth for type identity.
@knutwannheden knutwannheden force-pushed the fix-stackoverflowerror-in-typeutils.isassignableto branch from 03a5551 to 67764bf Compare April 2, 2026 08:41
@knutwannheden knutwannheden changed the title Fix cyclic type hierarchies in Python type mapping Fix StackOverflowError from self-referential supertype in Python type mapping Apr 2, 2026
@knutwannheden knutwannheden merged commit 300f097 into main Apr 2, 2026
1 check passed
@knutwannheden knutwannheden deleted the fix-stackoverflowerror-in-typeutils.isassignableto branch April 2, 2026 10:49
@github-project-automation github-project-automation bot moved this from In Progress to Done in OpenRewrite Apr 2, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

1 participant