laravel/framework · error · BadMethodCallException

Call to undefined method %s::%s()

Error message

Call to undefined method %s::%s()

What it means

PendingHasThroughRelationship is a placeholder returned while defining has-one/has-many-through via the pending ->has('Relation') syntax. Its __call() magic only forwards methods starting with 'has' to has(); any other method name is undefined and throws BadMethodCallException naming the class and method.

Source

Thrown at src/Illuminate/Database/Eloquent/PendingHasThroughRelationship.php:115

        return $returnedRelation;
    }

    /**
     * Handle dynamic method calls into the model.
     *
     * @param  string  $method
     * @param  array  $parameters
     * @return mixed
     *
     * @throws \BadMethodCallException
     */
    public function __call($method, $parameters)
    {
        if (Str::startsWith($method, 'has')) {
            return $this->has((new Stringable($method))->after('has')->lcfirst()->toString());
        }

        throw new BadMethodCallException(sprintf(
            'Call to undefined method %s::%s()', static::class, $method
        ));
    }
}

View on GitHub (pinned to bd6b5437e6)

Solutions

  1. Resolve the relationship first by calling ->has('relationName') (or hasXxx) before chaining query methods.
  2. Verify the method name you intend exists; use the camelCased distant relation name after 'has' (e.g. hasPosts()).
  3. If you need query constraints, define them via the closure form of has(): ->has(fn ($r) => $r->where(...)).

Example fix

// before
$model->posts()->throughAuthor()->latest(); // throws

// after
$model->throughAuthor()->hasPosts()->latest();
Defensive patterns

Strategy: type-guard

Validate before calling

if (! $pending instanceof \Illuminate\Database\Eloquent\PendingHasThroughRelationship
    || ! str_starts_with($method, 'has')) {
    throw new \BadMethodCallException("Unsupported call on pending relationship: {$method}");
}
$pending->{$method}();

Type guard

function isPendingHasCall(string $method): bool {
    return str_starts_with($method, 'has');
}

Try / catch

try {
    $pending->{$method}();
} catch (\BadMethodCallException $e) {
    if (str_contains($e->getMessage(), 'Call to undefined method')) {
        // resolve relation via has() first
    }
    throw $e;
}

Prevention

When it happens

Trigger: Chaining an arbitrary method on a pending through-relationship builder that does not start with 'has', e.g. $model->throughRelation()->someMethod() where someMethod is neither 'has' nor a has-prefixed accessor.

Common situations: Misunderstanding the pending relationship API and treating it as a full Builder; typos in relationship method names; calling query helpers (where, orderBy) directly on the pending object instead of the resolved relation.

Related errors


AI-assisted analysis of laravel/framework@bd6b5437e6 (2026-08-06). Data as JSON: /data/errors/8c427cecfe196d45.json. Report an issue: GitHub.