Error HTTP 500 yang muncul sporadis hanya pada fitur interaktif sering berakar dari pemanggilan prop parsial. Pada aplikasi Laravel yang menggunakan Inertia.js, halaman sering kali berjalan normal saat diakses langsung (initial visit), namun mendadak mengalami crash ketika frontend memicu router.reload({ only: ['...'] }).

Gejala: Initial Visit 200 OK, Partial Reload 500

Saat pengguna memuat halaman untuk pertama kali, Inertia merender komponen bersama props dasar. Prop berat yang dibungkus Inertia::lazy() diabaikan oleh backend demi menghemat waktu respons.

Masalah muncul ketika frontend meminta prop tersebut secara spesifik:

router.reload({ only: ['activities'] });

Request ini mengirimkan header HTTP berikut ke backend:

X-Inertia: true
X-Inertia-Partial-Component: Organizations/Show
X-Inertia-Partial-Data: activities

Respons server langsung berstatus 500 Internal Server Error, memutus alur kerja frontend.

Root Cause: Eloquent Strict Mode dalam Evaluasi Closure

Akar masalah ada pada kombinasi dua fitur: Laravel Strict Mode (Model::preventLazyLoading()) dan evaluasi deferred closure pada Inertia.

Pada initial visit, closure di dalam Inertia::lazy() tidak dieksekusi sama sekali, sehingga query relasi yang belum di-eager-load tidak pernah dipanggil. Ketika partial reload meminta data tersebut, Inertia mengeksekusi closure terkait. Jika model induk tidak memuat relasi tersebut sebelumnya, Eloquent mencoba melakukan lazy load secara dinamis.

Jika mode ketat aktif di AppServiceProvider:

Model::preventLazyLoading(! app()->isProduction());

Maka Laravel melempar eksepsi alih-alih mengeksekusi query N+1 otomatis.

Diagnosis: Membaca Stack Trace

Buka berkas storage/logs/laravel.log. Log menunjukkan titik kegagalan secara spesifik:

[2024-03-24 10:14:22] local.ERROR: Attempted to lazy load [activities] on model [App\Models\Organization] but lazy loading is disabled. {"userId":1,"exception":"[object] (Illuminate\\Database\\LazyLoadingViolationException(code: 0): Attempted to lazy load [activities] on model [App\\Models\\Organization] at /app/vendor/laravel/framework/src/Illuminate/Database/Eloquent/Model.php:844)"}

Stack trace memperlihatkan bahwa pemanggilan relasi terjadi di dalam definisi closure controller saat serialisasi prop berlangsung.

Solusi Kode: Eager Loading dan Isolasi Query

1. Pola Bermasalah

Mengakses relasi langsung dari model instance yang belum memuatnya:

public function show(Organization $organization)
{
    return Inertia::render('Organizations/Show', [
        'organization' => $organization,
        // Crash saat dipanggil partial reload:
        'activities' => Inertia::lazy(fn () => $organization->activities),
    ]);
}

2. Perbaikan: Explicit Eager Loading

Gunakan load() pada instance model jika relasi belum dimuat, atau jalankan query langsung melalui builder relasi untuk mencegah over-fetching data induk.

public function show(Organization $organization)
{
    return Inertia::render('Organizations/Show', [
        'organization' => $organization,
        // Solusi: Query langsung via relasi atau gunakan loadMissing()
        'activities' => Inertia::lazy(function () use ($organization) {
            return $organization->activities()
                ->with('user:id,name')
                ->latest()
                ->limit(20)
                ->get();
        }),
    ]);
}

Catatan: Menjalankan query langsung via $organization->activities()->get() menghasilkan builder query baru yang bersih. Pendekatan ini lebih optimal daripada mengeksekusi $organization->load('activities') yang memutasi state model pada memori.

Verifikasi: Integration Test dengan assertInertia

Uji skenario partial reload secara eksplisit dalam test suite untuk memastikan relasi tidak melanggar aturan lazy loading.

public function test_partial_reload_evaluates_lazy_prop_safely(): void
{
    $organization = Organization::factory()
        ->hasActivities(3)
        ->create();

    $this->actingAs($user = User::factory()->create())
        ->get(route('organizations.show', $organization), [
            'X-Inertia' => 'true',
            'X-Inertia-Partial-Component' => 'Organizations/Show',
            'X-Inertia-Partial-Data' => 'activities',
        ])
        ->assertOk()
        ->assertInertia(fn ($page) => $page
            ->component('Organizations/Show')
            ->has('activities', 3)
            ->missing('organization')
        );
}

Uji coba ini mengonfirmasi dua hal: respons bernilai 200 OK tanpa exception dari model strict mode, dan Inertia memfilter props dengan benar tanpa memuat prop yang tidak diminta.