symfony/routing · error · BadMethodCallException

Method " " not found on " " when importing routing resource…

Error message

Method "%s" not found on "%s" when importing routing resource "%s".

What it means

After resolving the object and method name from the resource string, ObjectLoader::load() verifies the method is callable on the loaded object. If not, it throws BadMethodCallException reporting the method name, the resolved object's type, and the original resource string, so the loader never calls an undefined method.

Solutions

  1. Correct the method name in the resource string to match a real public method on the service
  2. Add an __invoke method to the class if you intend to call the service directly
  3. Verify which class the service id resolves to (debug:container) — the error message shows get_debug_type of the actual object
  4. If the method was renamed, update the routing config to the new name

Example fix

# before
app_routes:
    resource: 'app.routing.loader::routeLoader'
    type: service

# after (method exists as loadRoutes on the service)
app_routes:
    resource: 'app.routing.loader::loadRoutes'
    type: service
Defensive patterns

Strategy: type-guard

Validate before calling

$id = explode('::', $resource)[0];
$obj = $container->get($id);
$method = explode('::', $resource)[1] ?? '__invoke';
if (!is_callable([$obj, $method])) { /* fix method name before calling the loader */ }

Type guard

function isCallableLoader(object $obj, string $method): bool { return is_callable([$obj, $method]); }

Try / catch

try { $collection = $loader->load($resource, 'service'); } catch (\BadMethodCallException $e) { /* correct method name or add __invoke per $e->getMessage() */ }

Prevention

When it happens

Trigger: Resource 'object_id::method' where the service has no such method; resource 'object_id' where the class has no __invoke; typos in the method name; method renamed during refactoring while routing config was not updated.

Common situations: Renaming a loader method without updating routing.yaml; pointing at an interface id whose implementation lacks __invoke; service id resolving to a different class than expected (autowiring alias changed).

Related errors


AI-assisted analysis of symfony/routing@83fa223250 (2026-09-14). Data as JSON: /api/errors/df8901f7d639e62d. Report an issue: GitHub.

Appendix: source

Thrown at Loader/ObjectLoader.php:48

     */
    abstract protected function getObject(string $id): object;

    /**
     * Calls the object method that will load the routes.
     */
    public function load(mixed $resource, ?string $type = null): RouteCollection
    {
        if (!preg_match('/^[^\:]+(?:::(?:[^\:]+))?$/', $resource)) {
            throw new \InvalidArgumentException(\sprintf('Invalid resource "%s" passed to the %s route loader: use the format "object_id::method" or "object_id" if your object class has an "__invoke" method.', $resource, \is_string($type) ? '"'.$type.'"' : 'object'));
        }

        $parts = explode('::', $resource);
        $method = $parts[1] ?? '__invoke';

        $loaderObject = $this->getObject($parts[0]);

        if (!\is_callable([$loaderObject, $method])) {
            throw new \BadMethodCallException(\sprintf('Method "%s" not found on "%s" when importing routing resource "%s".', $method, get_debug_type($loaderObject), $resource));
        }

        $routeCollection = $loaderObject->$method($this, $this->env);

        if (!$routeCollection instanceof RouteCollection) {
            $type = get_debug_type($routeCollection);

            throw new \LogicException(\sprintf('The "%s::%s()" method must return a RouteCollection: "%s" returned.', get_debug_type($loaderObject), $method, $type));
        }

        // make the object file tracked so that if it changes, the cache rebuilds
        $this->addClassResource(new \ReflectionClass($loaderObject), $routeCollection);

        return $routeCollection;
    }

    private function addClassResource(\ReflectionClass $class, RouteCollection $collection): void
    {

View on GitHub (pinned to 83fa223250)