{"record":{"id":"2b51bbe2420520d9","repo":"symfony/routing","slug":"the-s-s-method-must-return-a-routecollection-s-returned","errorCode":null,"errorMessage":"The \"%s::%s()\" method must return a RouteCollection: \"%s\" returned.","messagePattern":"The \"(.+?)::(.+?)\\(\\)\" method must return a RouteCollection: \"(.+?)\" returned\\.","errorType":"exception","errorClass":"LogicException","httpStatus":null,"severity":"error","filePath":"Loader/ObjectLoader.php","lineNumber":56,"sourceCode":"        if (!preg_match('/^[^\\:]+(?:::(?:[^\\:]+))?$/', $resource)) {\n            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'));\n        }\n\n        $parts = explode('::', $resource);\n        $method = $parts[1] ?? '__invoke';\n\n        $loaderObject = $this->getObject($parts[0]);\n\n        if (!\\is_callable([$loaderObject, $method])) {\n            throw new \\BadMethodCallException(\\sprintf('Method \"%s\" not found on \"%s\" when importing routing resource \"%s\".', $method, get_debug_type($loaderObject), $resource));\n        }\n\n        $routeCollection = $loaderObject->$method($this, $this->env);\n\n        if (!$routeCollection instanceof RouteCollection) {\n            $type = get_debug_type($routeCollection);\n\n            throw new \\LogicException(\\sprintf('The \"%s::%s()\" method must return a RouteCollection: \"%s\" returned.', get_debug_type($loaderObject), $method, $type));\n        }\n\n        // make the object file tracked so that if it changes, the cache rebuilds\n        $this->addClassResource(new \\ReflectionClass($loaderObject), $routeCollection);\n\n        return $routeCollection;\n    }\n\n    private function addClassResource(\\ReflectionClass $class, RouteCollection $collection): void\n    {\n        do {\n            if (is_file($class->getFileName())) {\n                $collection->addResource(new FileResource($class->getFileName()));\n            }\n        } while ($class = $class->getParentClass());\n    }\n}\n","sourceCodeStart":38,"sourceCodeEnd":74,"githubUrl":"https://github.com/symfony/routing/blob/83fa223250b50f4f018c011e101c330e65ac63cc/Loader/ObjectLoader.php#L38-L74","documentation":"ObjectLoader::load() calls a loader method on a routing resource object (a class with #[Route] attributes or a load() method) and requires it to return a RouteCollection. Symfony throws this LogicException when the method returns something else (null, an array, another object). This is an internal contract between the router and resource loader classes.","triggerScenarios":"A resource class's load(Object $resource, ?string $type = null) method (or a method named by the resource type) returns null early, returns an array instead of RouteCollection, or has a typo in return path that skips the return statement.","commonSituations":"Hand-written resource loader classes for annotation/attribute routing; a custom loader method accidentally returning $routes->all() (an array) or returning nothing on an early-exit branch; refactoring that changed the return type without updating all returns.","solutions":["Ensure the loader method returns a RouteCollection on every code path: $collection = new RouteCollection(); ...; return $collection;","Fix methods that return $collection->all() or an iterator — return the RouteCollection itself","Add a RouteCollection return type declaration to the method so PHP enforces the contract at runtime","If the method legitimately has no routes, return an empty new RouteCollection() instead of null"],"exampleFix":"// before\npublic function loadRoutes(): array\n{\n    return $this->routes->all();\n}\n// after\npublic function loadRoutes(): RouteCollection\n{\n    return $this->routes;\n}","handlingStrategy":"validation","validationCode":"if (!$routes instanceof \\Symfony\\Component\\Routing\\RouteCollection) { throw new \\LogicException('Loader must return a RouteCollection'); }","typeGuard":"function isRouteCollection(mixed $v): bool { return $v instanceof \\Symfony\\Component\\Routing\\RouteCollection; }","tryCatchPattern":"try { $collection = $loaderObject->load($resource, $env); } catch (\\LogicException $e) { // log loader class/method, fix return type }","preventionTips":["Declare RouteCollection as the return type on every loader method","Return an empty RouteCollection instead of null when there are no routes","Add a unit test asserting each loader method returns RouteCollection"],"tags":["routing","php","type-error","symfony"],"backgroundTag":"type-mismatch","analyzedSha":"83fa223250b50f4f018c011e101c330e65ac63cc","analyzedAt":"2026-09-14T03:19:46.280Z","contentChangedAt":"2026-09-14T03:19:46.280Z","schemaVersion":2},"datasetVersion":"2026-09-16T09:17:16.951Z"}