oven-sh/bun · error · Error

${typeName}: 'internal: true' on a property is not implement

Error message

${typeName}: 'internal: true' on a property is not implemented (no users today; the visitChildren plumbing for it was never wired up consistently). Use 'cache: true' or add it to 'values' instead.

What it means

A deliberate guard in generate-classes.ts: properties in *.classes.ts files cannot use `internal: true`. Although the option appears in the schema, the GC visitChildren plumbing it implies was never wired up consistently, so the generator hard-rejects it instead of emitting broken tracing code. The message points at the two supported alternatives: `cache: true` (getter whose result is cached and traced) or adding the slot to the class `values` array.

Source

Thrown at src/codegen/generate-classes.ts:1064

      values.push([name, cacheName]);
    }
  }

  return values;
}

function generateClassHeader(typeName, obj: ClassDefinition) {
  var { klass, proto, JSType = "ObjectType", values = [] } = obj;

  const name = className(typeName);

  if (obj.estimatedSize) {
    externs += `extern JSC_CALLCONV size_t ${symbolName(typeName, "estimatedSize")}(void* ptr);` + "\n";
  }

  for (const a of [...Object.values(klass), ...Object.values(proto)]) {
    if (a.internal === true) {
      throw new Error(
        `${typeName}: 'internal: true' on a property is not implemented (no users today; the visitChildren plumbing for it was never wired up consistently). Use 'cache: true' or add it to 'values' instead.`,
      );
    }
  }
  const DECLARE_VISIT_CHILDREN =
    values.length ||
    obj.estimatedSize ||
    obj.valuesArray ||
    [...Object.values(klass), ...Object.values(proto)].find(a => a.cache === true)
      ? "DECLARE_VISIT_CHILDREN;\n"
      : "";

  var weakOwner = "";
  var weakInit = ``;
  if (obj.hasPendingActivity) {
    weakInit = `m_weakThis = JSC::Weak<${name}>(this, getOwner());`;
    weakOwner = `
    JSC::Weak<${name}> m_weakThis;

View on GitHub (pinned to 8c5296ac45)

Solutions

  1. Replace `internal: true` with `cache: true` if the property is a JS-visible getter whose value should be retained and GC-traced
  2. Or declare the field in the class's `values` array so it participates in visitChildren through the normal values plumbing
  3. If neither fits, the property likely should not be in the definition at all — implement it as a manual C++/Rust method

Example fix

// before (Foo.classes.ts)
proto: {
  socket: { internal: true },
}

// after
proto: {
  socket: { cache: true },
}
Defensive patterns

Strategy: validation

Validate before calling

// reject `internal: true` before running codegen
for (const [name, prop] of Object.entries({ ...obj.klass, ...obj.proto })) {
  if ((prop as any)?.internal === true) {
    throw new Error(`${obj.name}.${name}: internal: true is not implemented — use cache: true or values`);
  }
}

Prevention

When it happens

Trigger: Declaring any klass or proto property with `internal: true` in a .classes.ts file, e.g. `proto: { underlying: { internal: true } }`, then running the class codegen step.

Common situations: Contributors trying to expose an internal accessor for C++/Rust-side state without making it a full cached property; copying old definitions from before the guard existed.

Related errors


AI-assisted analysis of oven-sh/bun@8c5296ac45 (2026-08-16). Data as JSON: /api/errors/d730941d2556090c. Report an issue: GitHub.