laravel/framework · error · RuntimeException

SQLite does not support altering primary keys.

Error message

SQLite does not support altering primary keys.

What it means

compileRenameIndex refuses to rename a PRIMARY KEY index on SQLite. SQLite has no ALTER statement to drop or replace a primary key definition, and renameIndex implements rename-by-drop-and-recreate, which is impossible for primaries. The guard fires after the source index is located, when $index['primary'] is true.

Solutions

  1. Exclude primary indexes from rename operations on SQLite (gate renameIndex by $index['primary'] === false using getIndexes()).
  2. If the primary must be renamed, recreate the table with the new primary definition (SQLite only supports table-rebuild for primary-key changes).
  3. Run the rename against Postgres/MySQL where primary keys can be dropped and re-added.

Example fix

// before
$table->renameIndex('users_pkey', 'users_id_primary');

// after (skip primaries on SQLite)
use Illuminate\Support\Facades\DB;

$index = collect(DB::connection()->getSchemaBuilder()->getIndexes('users'))
    ->firstWhere('name', 'users_pkey');

if ($index && ! $index['primary']) {
    $table->renameIndex('users_pkey', 'users_id_primary');
}
Defensive patterns

Strategy: validation

Validate before calling

use Illuminate\Support\Facades\DB;

$index = collect(DB::connection()->getSchemaBuilder()->getIndexes('users'))
    ->firstWhere('name', 'users_pkey');

if ($index && ! $index['primary']) {
    $table->renameIndex('users_pkey', 'users_id_primary');
}

Type guard

function indexIsRenamable(string $table, string $name): bool {
    $i = collect(\Illuminate\Support\Facades\DB::connection()->getSchemaBuilder()->getIndexes($table))
        ->firstWhere('name', $name);
    return $i !== null && ! $i['primary'];
}

Prevention

When it happens

Trigger: Calling $table->renameIndex('sqlite_autoindex_...', 'new_name') (or the named primary key) on a SQLite table where the matched index is a primary key.

Common situations: Generic rename migrations that iterate over all indexes including primaries; renaming the implicit primary index created by $table->id(); cross-database migrations that name the primary on Postgres/MySQL but hit SQLite in tests.

Related errors


AI-assisted analysis of laravel/framework@e0f6eb3518 (2026-08-11). Data as JSON: /api/errors/9b52e753fe9d8804. Report an issue: GitHub.

Appendix: source

Thrown at src/Illuminate/Database/Schema/Grammars/SQLiteGrammar.php:647

     *
     * @param  \Illuminate\Database\Schema\Blueprint  $blueprint
     * @param  \Illuminate\Support\Fluent  $command
     * @return array
     *
     * @throws \RuntimeException
     */
    public function compileRenameIndex(Blueprint $blueprint, Fluent $command)
    {
        $indexes = $this->connection->getSchemaBuilder()->getIndexes($blueprint->getTable());

        $index = Arr::first($indexes, fn ($index) => $index['name'] === $command->from);

        if (! $index) {
            throw new RuntimeException("Index [{$command->from}] does not exist.");
        }

        if ($index['primary']) {
            throw new RuntimeException('SQLite does not support altering primary keys.');
        }

        if ($index['unique']) {
            return [
                $this->compileDropUnique($blueprint, new IndexDefinition(['index' => $index['name']])),
                $this->compileUnique($blueprint,
                    new IndexDefinition(['index' => $command->to, 'columns' => $index['columns']])
                ),
            ];
        }

        return [
            $this->compileDropIndex($blueprint, new IndexDefinition(['index' => $index['name']])),
            $this->compileIndex($blueprint,
                new IndexDefinition(['index' => $command->to, 'columns' => $index['columns']])
            ),
        ];
    }

View on GitHub (pinned to e0f6eb3518)