laravel/framework · error · ClassMorphViolationException

No morph map defined for model [{$class}].

Error message

No morph map defined for model [{$class}].

What it means

When Relation::requireMorphMap() is enabled, every morphable model must be registered in the morph map before its class name is used as a morph type. getMorphClass() throws ClassMorphViolationException if the model is absent from the map, preventing ambiguous class-name storage across deployments.

Source

Thrown at src/Illuminate/Database/Eloquent/Concerns/HasRelationships.php:1038

     *
     * @return string
     *
     * @throws \Illuminate\Database\ClassMorphViolationException
     */
    public function getMorphClass()
    {
        $morphMap = Relation::morphMap();

        if (! empty($morphMap) && in_array(static::class, $morphMap)) {
            return array_search(static::class, $morphMap, true);
        }

        if (static::class === Pivot::class) {
            return static::class;
        }

        if (Relation::requiresMorphMap()) {
            throw new ClassMorphViolationException($this);
        }

        return static::class;
    }

    /**
     * Create a new model instance for a related model.
     *
     * @template TRelatedModel of \Illuminate\Database\Eloquent\Model
     *
     * @param  class-string<TRelatedModel>  $class
     * @return TRelatedModel
     */
    protected function newRelatedInstance($class)
    {
        return tap(new $class, function ($instance) {
            if (! $instance->getConnectionName()) {
                $instance->setConnection($this->getConnectionName());

View on GitHub (pinned to bd6b5437e6)

Solutions

  1. Register the model in the morph map, typically in AppServiceProvider::boot(): Relation::morphMap(['alias' => Model::class]).
  2. Confirm Relation::requireMorphMap() is intended; if not, do not enable it.
  3. Add a startup test that iterates morphable models and asserts they appear in Relation::morphMap().

Example fix

// before
Relation::requireMorphMap();
// Post is morphable but never registered -> throws on create

// after (in AppServiceProvider::boot)
Relation::morphMap([
    'post'    => \App\Models\Post::class,
    'video'   => \App\Models\Video::class,
]);
Defensive patterns

Strategy: validation

Validate before calling

use Illuminate\Database\Eloquent\Relations\Relation;
if (Relation::requiresMorphMap()) {
    foreach ([\App\Models\Post::class, \App\Models\Video::class] as $m) {
        if (! in_array($m, Relation::morphMap(), true)) {
            throw new \RuntimeException("Morph map missing for {$m}");
        }
    }
}

Type guard

function isRegisteredInMorphMap(string $modelClass): bool
{
    return in_array($modelClass, \Illuminate\Database\Eloquent\Relations\Relation::morphMap(), true);
}

Try / catch

try {
    return $model->getMorphClass();
} catch (\Illuminate\Database\ClassMorphViolationException $e) {
    \Illuminate\Database\Eloquent\Relations\Relation::morphMap([
        strtolower(class_basename($e->model)) => $e->model,
    ]);
    return $model->getMorphClass();
}

Prevention

When it happens

Trigger: Calling Relation::requireMorphMap(); using morphMany/morphTo/morphMap without registering the model via Relation::morphMap(['post' => Post::class]); then triggering any operation that needs the morph alias (creating a polymorphic record, serializing, whereMorphedTo with a model instance).

Common situations: New morphable model added without a morph-map entry; enabling requireMorphMap mid-project; package models not registered; CI/local config drift where morph map is set in AppServiceProvider but skipped in a worker.

Related errors


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