Skip to content

AOT: require('./mod') from inside a class method returns a non-callable value #668

Closed

Description

@proggeramlug

Summary

Under perry compile, a require('./helper') call inside a class method body returns something whose method properties throw TypeError: value is not a function when called. Node + Bun handle the same source (treated as CJS-compatible) and return a real module object.

require() was used in @perryts/redis to break a module-import cycle between connection.ts and pipeline.ts. Workaround: convert to a top-level static ES import — ESM cycles are legal as long as the cross-imports are referenced inside function bodies (which they are here).

Environment

  • perry 0.5.795
  • macOS 26.4 / Apple M1 Max

Minimal repro

// helper.ts
export function greet(name: string): string {
    return 'hello, ' + name;
}
// repro.ts
class C {
    load(): unknown {
        return require('./helper');
    }
}
const c = new C();
const m = c.load() as any;
console.log('typeof m:    ', typeof m, '  has greet:', m && typeof m.greet);
if (m && typeof m.greet === 'function') console.log(m.greet('world'));
$ perry compile /tmp/repro.ts -o /tmp/repro && /tmp/repro
TypeError: value is not a function
    at <anonymous>
exit=1

Bun output (correct):

typeof m:     object   has greet: function
hello, world

Node + tsx (correct):

typeof m:     object   has greet: function
hello, world

Impact

Any driver/library that uses inline require() to break import cycles is broken under AOT. The fix on the caller side is straightforward (static ESM import) but is a silent runtime failure rather than a compile error, so it's hard to discover without running.

Suggested behavior

Either lower require(literalPath) to an ESM-equivalent static module reference at compile time, or fail at compile with a clear "CJS require is not supported under perry compile — use static import" message.

Activity

  1. added a commit that references this issue on May 11, 2026
  2. added a commit that references this issue on May 17, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

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