{"record":{"id":"490b4c4e758e6fd2","repo":"larastan/larastan","slug":"is-not-a-model","errorCode":null,"errorMessage":" is not a Model.","messagePattern":" is not a Model\\.","errorType":"exception","errorClass":"InvalidArgumentException","httpStatus":null,"severity":"error","filePath":"src/Methods/BuilderHelper.php","lineNumber":294,"sourceCode":"    public function getBuilderType(string $builderClassName, Type $modelType): ObjectType\n    {\n        if (! $this->reflectionProvider->getClass($builderClassName)->isGeneric()) {\n            return new ObjectType($builderClassName);\n        }\n\n        return new GenericObjectType($builderClassName, [$modelType]);\n    }\n\n    /**\n     * @throws MissingMethodFromReflectionException\n     * @throws InvalidArgumentException\n     */\n    public function determineBuilderName(string $modelClassName): string\n    {\n        $modelReflection = $this->reflectionProvider->getClass($modelClassName);\n\n        if (! $modelReflection->is(Model::class)) {\n            throw new InvalidArgumentException($modelClassName . ' is not a Model.');\n        }\n\n        $method = $modelReflection->getNativeMethod('newEloquentBuilder');\n\n        if ($method->getDeclaringClass()->getName() === Model::class) {\n            $attrs = $modelReflection->getNativeReflection()->getAttributes('Illuminate\\Database\\Eloquent\\Attributes\\UseEloquentBuilder'); //@phpstan-ignore argument.type (Attribute class might not exist)\n\n            if ($attrs !== []) {\n                $expr =  $attrs[0]->getArgumentsExpressions()[0];\n\n                if ($expr instanceof ClassConstFetch && $expr->class instanceof Name) {\n                    return $expr->class->toString();\n                }\n            }\n        }\n\n        $returnType = $method->getVariants()[0]->getReturnType();\n","sourceCodeStart":276,"sourceCodeEnd":312,"githubUrl":"https://github.com/larastan/larastan/blob/79091ad281b47871ec2c0f7d1aa61b042a1e15fc/src/Methods/BuilderHelper.php#L276-L312","documentation":"determineBuilderName() in BuilderHelper resolves the Eloquent builder class used for a model, and it only accepts class names whose ClassReflection is exactly Illuminate\\Database\\Eloquent\\Model (checked via ->is(Model::class)). Any other class name passed in makes Larastan throw an InvalidArgumentException ('X is not a Model.'). This is an internal invariant: callers such as determineBuilderClass must only pass model class names.","triggerScenarios":"A code path calls determineBuilderName()/determineBuilderClass() with a class name that is not (a subclass resolution of) Eloquent\\Model — e.g. a Builder or query class name was passed where a model class was expected.","commonSituations":"Custom relation or builder code paths feeding a non-model type into model-based builder resolution; misconfigured generic template parameters where TModel was substituted with a builder or plain class instead of a model; internal extension bugs after Laravel/PPHPStan upgrades.","solutions":["Check the calling code/PHPDoc and pass the model class name (a subclass of Illuminate\\Database\\Eloquent\\Model) instead of the builder or other class.","If you hit it on your own code, inspect @template TModel annotations on the custom builder/relation so generics resolve to the model, not the builder.","If it reproduces on plain Laravel models, file a Larastan issue with a minimal reproducer — it indicates a wrong class reached determineBuilderClass."],"exampleFix":"// before (custom builder annotated wrong)\n/** @template TModel of \\App\\Builders\\PostBuilder */\nclass Post extends Model {}\n// after\nclass Post extends Model {}\n/** @extends Builder<Post> */\nclass PostBuilder extends Builder {}","handlingStrategy":"type-guard","validationCode":"// before relying on builder resolution\nif (! is_subclass_of($modelClassName, \\Illuminate\\Database\\Eloquent\\Model::class) && $modelClassName !== \\Illuminate\\Database\\Eloquent\\Model::class) {\n    throw new \\InvalidArgumentException(\"$modelClassName must be an Eloquent Model.\");\n}","typeGuard":"function isEloquentModel(string $class): bool\n{\n    return class_exists($class) && (is_subclass_of($class, \\Illuminate\\Database\\Eloquent\\Model::class) || $class === \\Illuminate\\Database\\Eloquent\\Model::class);\n}","tryCatchPattern":null,"preventionTips":["Only pass model class names (not builders, relations, or tables) into model-based analysis APIs.","Keep @template TModel annotations on custom builders bound to the model class, not the builder itself.","When writing custom relations/builders, mirror an existing Larastan-tested pattern."],"tags":["static-analysis","eloquent","invalid-argument","phpstan-extension"],"backgroundTag":"invalid-argument-value","analyzedSha":"79091ad281b47871ec2c0f7d1aa61b042a1e15fc","analyzedAt":"2026-09-15T22:55:40.008Z","contentChangedAt":"2026-09-15T22:55:40.008Z","schemaVersion":2},"datasetVersion":"2026-09-23T02:17:17.105Z"}