Runtime Error 97: “Can't call Friend procedure on an object that isn't an instance of the defining class,” explained and fixed

Error 97, “Can't call Friend procedure on an object that isn't an instance of the defining class”, is about VBA's Friend scope. A Friend procedure is visible throughout its own project but hidden outside it, and VBA adds a strict condition: it may only be called through a variable declared as the exact class that defines it. Call the same procedure through a variable typed as a base class, an interface the class implements, or Object, and error 97 fires, even though the object really is an instance of the right class. It is a declaration bug, not an object bug.

For people who just run the program

  1. This error is for the person who maintains the code. It appears in component-style VBA projects (class libraries, add-ins) rather than in record-and-run macros, and no document or setting influences it.
  2. Note which feature of the tool triggered it. Friend calls are usually confined to a few internal operations; the feature identifies the call site.
  3. Restarting will not change it. The declared type of the variable is fixed in the code, so the same action fails identically.
  4. Pass on the error number verbatim. Error 97 is uncommon enough that the number alone tells the maintainer the fix: redeclare the variable as the defining class.

For people who write the code

  1. Declare the variable as the defining class. That single change is the documented remedy:
  2. Dim widget As Object
    Set widget = New CWidget
    widget.InternalReset   ' error 97: called through Object
    
    Dim widget2 As CWidget
    Set widget2 = New CWidget
    widget2.InternalReset  ' fine: declared as the defining class
  3. Or widen the procedure's scope deliberately. If callers legitimately hold the object through an interface or base type, Friend is the wrong scope: make the procedure Public and accept the wider visibility, or add a Public wrapper on the class that interface-typed callers can use.
  4. Audit Implements relationships. Classes that implement an interface invite interface-typed variables everywhere. Any member the design intends to call through the concrete class must be documented as such, or the next caller rediscovers error 97.
Casting does not help. Assigning the object to an Object variable “for flexibility” and calling the Friend member through it is exactly the failing pattern, even for one line. The declared type at the call site is what VBA checks.

If it still happens

If the variable is declared as the defining class and error 97 persists, check that the object assigned is truly an instance of that class and not of a look-alike class from another project with the same name. Two CWidget classes in two referenced projects are different types, and Friend knows it even when the names match.

Common questions

What is a Friend procedure? A procedure scoped between Private and Public: callable from anywhere inside its own project, invisible outside it. It is used in class modules to expose members to sibling code without publishing them to other projects.

Why is Friend stricter than Public about the variable type? Because Friend members are not part of the class's public interface or its vtable in the usual way. VBA resolves them through the exact class type, so the compiler and runtime require the variable to be declared as that class.

Related errors

Runtime Error 430 · Runtime Error 438 · Runtime Error 429