Skip to content

redis npm package: createClient(...).connect() — TypeError 'Cannot read properties of undefined (reading connect)' on perry-compiled binary #605

Description

@proggeramlug

Summary

createClient(...) from the redis npm package returns a value whose .connect() is undefined under perry. Same code on Node creates a working RedisClient and calls .connect() cleanly.

Reproducer

tests/release/packages/redis-pubsub/ fixture (added to the release-sweep harness this cycle):

// entry.ts
import { createClient } from "redis";

async function main(): Promise<void> {
    const url = process.env.REDIS_URL ?? "redis://127.0.0.1:18903";
    const sub = createClient({ url });
    const pub = createClient({ url });
    await sub.connect();
    await pub.connect();

    const received: string = await new Promise<string>((resolve) => {
        sub.subscribe("greetings", (message: string) => resolve(message));
        setTimeout(() => { pub.publish("greetings", "hello"); }, 50);
    });
    console.log(`received=${received}`);

    await sub.unsubscribe("greetings");
    await sub.quit();
    await pub.quit();
}
main();
{
  "dependencies": { "redis": "^4.7.0" },
  "perry": { "compilePackages": ["redis"] }
}

A real redis-server binary on port 18903 (the fixture launches one with redis-server --port 18903 --bind 127.0.0.1 --save '' before the run; teardown is kill on the trapped EXIT).

Expected (from Node)

received=hello

Actual (from perry-compiled binary)

TypeError: Cannot read properties of undefined (reading 'connect')

— so sub (the value returned by createClient({ url })) is either undefined itself, or its prototype doesn't have a connect method. The call dies at await sub.connect() before any actual redis connection is attempted.

Why this matters

redis is a pure-JS npm package (no native bindings). It's the canonical example for compilePackages — if it doesn't work, neither do most pubsub / cache / queue libs.

Likely root cause: factory-function-returning-object pattern that perry's class/proto resolution doesn't handle. createClient({...}) is not a constructor — it's a factory that builds and returns a RedisClient instance. If perry's HIR doesn't recognize the returned object's class, all method calls miss the vtable.

Worth bisecting against the simpler createClient().connect() (no await, no options) shape to confirm the issue is in the factory return path, not in the await chain.

Environment

  • Perry 0.5.699
  • redis ^4.7.0
  • redis-server (Homebrew) v8.4.0
  • macOS 26.4 / arm64
  • Discovered via scripts/release_sweep.sh --tier=3 (tests/release/packages/redis-pubsub/)

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugConfirmed defect or regressionparityCompatibility gap with Node.js, ECMAScript, or the supported ecosystem

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions