Laravel error
Laravel: SQLSTATE[42S02] Base table or view not found
The error
SQLSTATE[42S02]: Base table or view not found: 1146 Table 'shop.orders' doesn't existThe query is valid and the table is not there. Where that happens tells you which of the five causes you have, and only one of them is a missing migration.
The error
Illuminate\Database\QueryException
SQLSTATE[42S02]: Base table or view not found: 1146
Table 'shop.orders' doesn't exist
Postgres words it differently and means the same thing:
SQLSTATE[42P01]: Undefined table: 7 ERROR: relation "orders" does not exist
Read the name before anything else
The message contains the database and the table the query asked for. Both are useful and both get skipped.
SHOW TABLES; -- MySQL
\dt -- PostgresComparing that list with the name in the error resolves most of these in under a minute, because the answer is usually either that the table has a different name than you expected or that you are connected to a different database than you expected.
The five causes
The migration has not run. The obvious one, and the least interesting.
php artisan migrate --forceWorth checking what the framework thinks has run, which is not the same as what is in your migrations folder:
php artisan migrate:statusIt ran somewhere else. The most common cause on a real system. A
migration executed against staging, or against the local database, while the
application is reading production. Or the web process uses one .env and a
queued worker was started with another. The database name in the error is the
evidence - compare it with the one in your connection config.
The model's table name is not the one you assumed. Eloquent derives the
table from the class name and pluralises it in English. Person becomes
people, Status becomes statuses, and a class named after a Turkish or
German business term becomes something nobody intended.
class OrderLine extends Model
{
protected $table = 'order_lines'; // say it rather than infer it
}The test database has no schema. A test that hits the database needs one, and the trait that builds it has to be on the test class:
uses(RefreshDatabase::class);Without it the suite runs against whatever the test connection points at, which on a fresh checkout or a CI runner is an empty database.
A deploy is halfway through. New code deployed before its migration ran, or a worker still running old code after a table was renamed. Queries against a table that exists in one version and not the other fail for as long as the two versions overlap.
The one that only happens in production
Table names are case sensitive on Linux and usually not on macOS. A model
referring to Orders while the table is orders works perfectly on a
developer's machine and fails on every server.
If the error appears only after deployment and the name looks right, compare the case character by character.
Renaming a table without an outage
The reason this error shows up during otherwise careful deploys is that a rename is two states with a gap between them, and requests arrive in the gap.
Do it in steps instead:
- Create the new table alongside the old one.
- Write to both, read from the old.
- Backfill, then switch reads to the new one.
- Stop writing the old one.
- Drop it in a later release.
Slower, and nothing fails while it happens - which is the trade every schema change on a live system is making, whether or not anybody decided it deliberately.
One step further along the same path is a foreign key that cannot find its parent. By then the table exists and the rows it points at do not.
The five-step shape above is what a locking schema change needs as well. Which of your migrations need it, and which are safe in one step, depends on your row counts, and we measure that.
