Às vezes, ao executar uma migração do Laravel, você obtém o erro: errno 150 "errno 150 "Foreign key constraint is incorrectly formed" que siginifica: “A restrição de chave estrangeira está formada incorretamente”. Este erro é causado principalmente porque sua coluna de chave estrangeira é declarada usando um tipo de dados diferente da coluna de chave relacionada na tabela de origem.

Principal causa para o erro “errno 150: Foreign key constraint is incorrectly formed”

A causa mais comum do erro é que a coluna de chave estrangeira é criada com o tipo errado, relacionado à coluna primária referenciada.

Já que increments() cria uma coluna do tipo integer sem sinal (unsigned), você precisa definir a coluna de chave estrangeira como inteiro unsigned também.

As migrações padrão no Laravel 6+ usam bigIncrements(), então você precisa usar o método unsignedBigInteger():

$table->unsignedBigInteger('order_id');

Para migrações padrão em versões mais antigas do Laravel, use o método unsignedInteger():

$table->unsignedInteger('order_id');

Ou:

$table->integer('order_id')->unsigned();

Veja um exemplo de migração com erro:

Schema::create('books', function (Blueprint $table) {
        $table->increments('id');
        $table->string('title');
        $table->timestamps();
        $table->softDeletes();
    });

Schema::create('orders', function (Blueprint $table) {
        $table->increments('id');
        $table->integer('book_id');
        $table->timestamps();
        $table->softDeletes();

        $table->foreign('book_id')->references('id')->on('books');

    });
}

Então, para resolver um erro como:

[Illuminate\Database\QueryException]
SQLSTATE[HY000]: General error: 1005 Can't create table orders.#sql-b5b_b2a (errno: 150 "Foreign key constraint is incorrectly formed") (SQL: alter table orders add constraint orders_book_id_foreign foreign key (book_id) references books (id))

[Doctrine\DBAL\Driver\PDOException]
SQLSTATE[HY000]: General error: 1005 Can't create table books.#sql-b5b_b2a (errno: 150 "Foreign key constraint is incorrectly formed")

Você deve alterar a linha que cria a coluna book_id:

Schema::create('books', function (Blueprint $table) {
        $table->increments('id');
        $table->string('title');
        $table->timestamps();
        $table->softDeletes();
    });

Schema::create('orders', function (Blueprint $table) {
        $table->increments('id');
        $table->unsignedBigInteger('book_id'); // altere esta linha
        $table->timestamps();
        $table->softDeletes();

        $table->foreign('book_id')->references('id')->on('books');

    });
}

Outras causas para o erro “Foreign key constraint is incorrectly formed”

Nome da tabela referenciada errado

Um dos pecados mais comuns de desenvolvedores, errar o nome de variáveis, tabelas, campos, etc. Então sim, um simples e inocente erro destes pode trazer a mensagem de erro: “errno 150 Foreign key constraint is incorrectly formed on Laravel Migration”. Basta corrigir a tabela na instrução de criação da chave estrangeira:

Schema::create('books', function (Blueprint $table) {
        $table->increments('id');
        ...
    });

Schema::create('orders', function (Blueprint $table) {
        $table->increments('id');
        $table->unsignedBigInteger('book_id'); 
        $table->foreign('book_id')->references('id')->on('book'); // corrija o nome para books
    });
}

Ordem dos arquivos Migration

Às vezes, o motivo desse erro é devido à ordem em que os arquivos de migração são listados ou erro devido à conversão de tipo.

Certifique-se sempre de que a migração do arquivo ao qual as restrições de chaves estrangeiras serão criadas ocorra após a migration principal. E também certifique-se de que é um unsignedBigInteger, embora a versão anterior do laravel (<5.4) possa ignorar esse erro de conversão de tipo.

Portanto, os arquivos de migração devem ser criados de forma que a migração pai venha primeiro e o arquivo de migração com a chave estrangeira em seguida.

Além disso, a chave estrangeira e o id primário na outra tabela devem ter propriedades exatamente semelhantes. Se o id primário for incrementado, faça a chave estrangeira integer('xxx_id')->unsigned();

MySQL MyISAM

Verifique o motor (engine) da sua tabela MySQL. Em alguns casos, você pode estar referenciando uma tabela MyISAM em uma tabela de origem InnoDB. Depois de alterar o mecanismo da tabela de referência para InnoDB, ele deve funcionar!

Isso pode ser causado quando as tabelas criadas antes da migração onde MyISAM de um sistema legado e as migradas são innoDB por padrão, então a mistura de tipos de tabela será um problema no meu caso.

Conclusões

Preste atenção ao criar chaves estrangeiras no Laravel Migration para criar as colunas estrangeiras com o mesmo tipo de dados das colunas originais, criando também os arquivos de migração na ordem correta.