Missing unique constraint on Jetstream team names (Laravel 9/Jetstream 2.x)
0 reputation · 17 Jul 2022, 06:22 UTC
0 reputation · 17 Jul 2022, 06:22 UTC
When using Laravel Jetstream 2.x with Laravel 9, the default team migration creates a teams table that includes a name string column but does not add a unique database constraint. This means two different users can create teams with identical names, and concurrent requests may result in race conditions that allow duplicate entries to be saved.
The documentation does not clarify whether this omission is intentional or an oversight, nor does it provide a built‑in mechanism to enforce uniqueness. Developers therefore must decide how to handle potential duplicates and whether to add a custom unique index or implement application‑level checks.
name column an intentional design choice in Jetstream 2.x, or is it an oversight that should be reported?34275 reputation · 17 Jul 2022, 16:46 UTC
The default Jetstream 2.x migration for Laravel 9 creates a name column without a UNIQUE index. The package documentation does not mention a unique constraint, and the source code defines the column as a plain string. This omission appears to be an implementation oversight rather than an intentional design choice.
SELECT name, COUNT(*) FROM teams GROUP BY name HAVING COUNT(*) > 1;
If duplicates are found, resolve them before adding the index.name column:
php artisan make:migration add_unique_index_to_teams_name --table=teams
Edit the migration to contain:
Schema::table('teams', function (Blueprint $table) {
$table->unique('name');
});
Run php artisan migrate.CreateTeam request to give early feedback:
'name' => ['required', 'string', 'max:255', 'unique:teams,name']
use Illuminate\Support\Facades\DB;
use Illuminate\Database\QueryException;
public function store(CreateTeam $request)
{
try {
DB::transaction(function () use ($request) {
$team = $request->user()->ownedTeams()->create([
'name' => $request->input('name'),
// …other fields
]);
});
} catch (QueryException $e) {
if ($e->errorInfo[1] == 1062) { // MySQL duplicate‑entry error code
return back()->withErrors(['name' => 'The team name has already been taken.']);
}
throw $e;
}
return redirect()->route('teams.index');
}
Do you have any existing duplicate team names in your teams table? If duplicates are present, the unique index will fail unless they are resolved first. Let me know the result of the SELECT query above, and I can advise on the safest next step.
Use comments to ask for clarification. Post a solution as an answer.
No question comments on this page.