Debug 500 saat integrasi Codex CLI hampir selalu mengarah ke satu fakta penting: proses web tidak berjalan dalam environment yang sama dengan terminal lokal Anda. Perintah yang sukses saat dijalankan manual bisa gagal total saat dipanggil dari Express, Laravel queue, worker supervisor, atau proses web lain karena PATH berbeda, ENV tidak terbaca, permission binary salah, working directory keliru, timeout terlalu pendek, atau stderr tidak pernah tercatat.
Jika gejalanya adalah “di terminal normal, di backend HTTP 500”, fokuskan investigasi ke cara proses server mengeksekusi CLI, bukan langsung menyalahkan prompt, model, atau logika aplikasi. Dalam konteks penggunaan Codex CLI seperti yang umum dibahas pada referensi implementasi bozhouDev/codex-orange-book, akar masalah paling sering ada pada boundary antara aplikasi backend dan proses shell.
Gejala yang Paling Sering Muncul
Pola masalahnya biasanya mirip:
- Menjalankan
codex ...langsung dari terminal berhasil. - Request API ke endpoint backend mengembalikan
HTTP 500. - Job queue gagal tanpa pesan error yang jelas.
- Log aplikasi hanya menampilkan
Command failedatauexit code 1. - Server seperti Nginx, PHP-FPM, Supervisor, systemd, atau container tampak sehat, tetapi eksekusi CLI tetap gagal.
Dalam praktiknya, masalah ini sering tersembunyi karena backend hanya memeriksa stdout, sementara detail kegagalan sebenarnya muncul di stderr. Akibatnya, aplikasi melempar 500 tanpa konteks yang bisa dipakai untuk diagnosis.
Kenapa Berjalan di Terminal tapi Gagal di Express atau Laravel Worker?
Terminal interaktif biasanya memuat banyak konfigurasi otomatis: profile shell, alias, PATH tambahan, token, directory default, dan user permission tertentu. Sebaliknya, proses web atau worker berjalan dengan kondisi yang lebih terbatas:
- User berbeda, misalnya
www-data,nginx, atau user service. PATHminimal, sehingga binary seperticodextidak ditemukan.- Variabel environment seperti API key tidak diwariskan ke worker.
- Current working directory bukan folder proyek yang Anda kira.
- Timeout request HTTP lebih pendek daripada durasi eksekusi CLI.
- Permission execute pada binary atau direktori kerja tidak memadai.
Jadi, meskipun command string terlihat benar, konteks eksekusinya berbeda secara signifikan.
Studi Kasus: Endpoint Backend Memanggil Codex CLI lalu Mengembalikan 500
Misalkan backend menerima request untuk menjalankan Codex CLI terhadap file tertentu. Secara lokal, Anda mencoba perintah yang sama di terminal dan berhasil. Namun saat endpoint dipanggil dari aplikasi, hasilnya 500.
Contoh gejala di Express
const { execFile } = require('child_process');
app.post('/run-codex', (req, res) => {
execFile('codex', ['run', '--json'], (error, stdout, stderr) => {
if (error) {
return res.status(500).json({ error: 'Codex execution failed' });
}
res.json({ output: stdout });
});
});Kode di atas tampak wajar, tetapi punya beberapa kelemahan:
- Mengandalkan binary
codextersedia diPATH. - Tidak mencatat
stderr. - Tidak menetapkan
cwd. - Tidak mengatur timeout secara eksplisit.
- Tidak mencatat environment yang relevan.
Contoh gejala di Laravel job
public function handle(): void
{
$result = Symfony\Component\Process\Process::fromShellCommandline('codex run --json');
$result->mustRun();
}
Pada worker queue, command ini bisa gagal walaupun sukses saat dijalankan manual oleh developer. Worker sering berjalan di environment berbeda dari sesi shell biasa.
Root Cause Umum yang Perlu Diperiksa
1. PATH berbeda sehingga binary codex tidak ditemukan
Ini akar masalah yang paling sering. Di terminal interaktif, PATH mungkin memuat lokasi instalasi CLI dari package manager atau direktori user. Di proses backend, PATH bisa sangat minim.
Contoh error yang sering muncul di log jika stderr dicatat:
spawn codex ENOENTatau:
sh: 1: codex: not foundKenapa ini terjadi? Karena shell login Anda mungkin memuat konfigurasi dari .zshrc, .bashrc, atau profile lain, sedangkan proses web tidak.
2. ENV tidak terbaca
Codex CLI atau lapisan integrasinya bisa bergantung pada environment variable tertentu, misalnya token, endpoint, atau konfigurasi runtime. Variabel itu tersedia di terminal Anda, tetapi tidak tersedia di Express process, PHP-FPM, Supervisor, atau queue worker.
Gejalanya bisa berupa:
authentication failed
missing API key
required environment variable is not setKenapa ini terjadi? Karena menyimpan ENV di shell profile tidak otomatis membuatnya tersedia untuk service manager atau worker yang sudah berjalan sejak sebelumnya.
3. Permission binary atau file kerja tidak sesuai
Proses backend mungkin berjalan sebagai user layanan yang tidak punya hak execute terhadap binary, atau tidak punya akses baca/tulis ke folder proyek, cache, temporary file, atau output file.
Contoh gejalanya:
Permission denied
EACCESKenapa ini terjadi? Karena Anda menguji command sebagai user pribadi, sedangkan proses web dijalankan oleh user berbeda dengan hak akses lebih sempit.
4. Working directory salah
Codex CLI kadang diharapkan berjalan dari direktori proyek tertentu, terutama jika command bergantung pada file relatif, konfigurasi lokal, atau konteks repo. Jika backend mengeksekusinya dari direktori lain, command bisa gagal walaupun binary ditemukan.
Gejalanya sering berupa:
file not found
config not found
no such file or directoryKenapa ini terjadi? Karena worker bisa start dari root service, direktori deploy, atau path default proses, bukan dari folder aplikasi yang Anda asumsikan.
5. Timeout terlalu pendek
Eksekusi CLI yang memanggil proses eksternal atau model bisa memerlukan waktu lebih lama daripada request HTTP biasa. Jika backend menunggu sinkron di dalam request dan timeout pendek, aplikasi bisa memotong proses lalu melempar 500 atau 504.
Gejala umum:
Process timed out after 30 secondsKenapa ini terjadi? Karena Anda memperlakukan CLI seperti operasi lokal cepat, padahal durasinya bergantung pada I/O, jaringan, file, dan beban sistem.
6. stderr tidak tercatat
Ini bukan root cause utama, tetapi penyebab debugging terasa buntu. Banyak implementasi hanya membaca stdout dan langsung mengembalikan 500 saat exit code non-zero. Padahal penjelasan error sebenarnya hampir selalu ada di stderr.
Urutan Investigasi yang Efektif
Jangan mulai dari tebakan. Gunakan urutan investigasi berikut agar diagnosis cepat dan bisa direproduksi.
Langkah 1: Catat command, exit code, stdout, stderr, cwd, dan PATH
Minimal, log harus menjawab pertanyaan berikut:
- Command apa yang benar-benar dijalankan?
- Binary path apa yang dipakai?
cwdsaat eksekusi di mana?PATHproses saat itu apa?- Exit code berapa?
- Apa isi
stderr? - Berapa lama proses berjalan?
Contoh logging yang lebih aman di Node.js:
const { execFile } = require('child_process');
const path = require('path');
app.post('/run-codex', (req, res) => {
const startedAt = Date.now();
const cwd = '/var/www/myapp';
const env = {
...process.env,
PATH: process.env.PATH || '/usr/local/bin:/usr/bin:/bin'
};
execFile('/usr/local/bin/codex', ['run', '--json'], { cwd, env, timeout: 120000 }, (error, stdout, stderr) => {
const durationMs = Date.now() - startedAt;
console.log(JSON.stringify({
event: 'codex_exec',
cwd,
durationMs,
hasError: !!error,
exitCode: error ? error.code : 0,
stderr: stderr ? stderr.slice(0, 4000) : '',
stdoutPreview: stdout ? stdout.slice(0, 1000) : ''
}));
if (error) {
return res.status(500).json({
error: 'Codex execution failed',
exitCode: error.code
});
}
res.json({ output: stdout });
});
});Poin pentingnya bukan format exact code, tetapi prinsip berikut:
- Gunakan absolute path ke binary bila memungkinkan.
- Tetapkan cwd secara eksplisit.
- Wariskan env yang dibutuhkan secara sadar, bukan kebetulan.
- Log stderr dan exit code.
Langkah 2: Verifikasi user proses backend
Cek proses web atau worker berjalan sebagai user apa. Setelah itu, ulangi command Codex CLI sebagai user tersebut, bukan sebagai user developer Anda.
Ini penting karena banyak masalah permission dan PATH hanya muncul pada user service.
Catatan: Jika command sukses sebagai user Anda tetapi gagal sebagai user service, fokuskan pemeriksaan ke PATH, permission, home directory, dan environment user service tersebut.
Langkah 3: Cetak environment minimum yang relevan
Anda tidak perlu mencetak seluruh environment ke log produksi. Cukup catat subset yang penting untuk diagnosis, misalnya:
PATHHOMEPWD- variabel aplikasi yang memang diperlukan untuk Codex CLI
Hindari mencatat secret mentah ke log. Jika perlu, log keberadaan nilainya, bukan isi penuh.
Contoh log yang aman:
{
"event": "codex_env_check",
"cwd": "/var/www/myapp",
"path": "/usr/bin:/bin",
"home": "/var/www",
"hasCodexToken": true
}Langkah 4: Pastikan binary benar-benar ada dan executable
Verifikasi lokasi binary yang dipakai backend. Jangan mengandalkan asumsi bahwa codex akan ditemukan otomatis. Jika perlu, simpan path binary di konfigurasi aplikasi.
Masalah yang sering terjadi:
- Binary terinstal hanya untuk user tertentu.
- Binary ada, tetapi tidak executable oleh user proses.
- Symlink valid di terminal pribadi, tetapi tidak untuk service environment.
Langkah 5: Validasi working directory dan file relatif
Jika command Anda membaca file input, template, repo, atau konfigurasi relatif, log path absolut yang benar-benar dipakai. Banyak bug terlihat seperti masalah CLI, padahal sebenarnya file yang dicari tidak ada di cwd proses.
Langkah 6: Ukur timeout dan durasi nyata
Jika eksekusi Codex CLI tidak selalu instan, jangan paksa berjalan sinkron di request HTTP tanpa kontrol. Log durasi aktual dan tentukan apakah tugas ini lebih cocok dipindahkan ke queue/job asinkron.
Contoh Log yang Membantu Menemukan Akar Masalah
Contoh pertama: binary tidak ditemukan.
{
"event": "codex_exec",
"cwd": "/var/www/myapp",
"durationMs": 12,
"hasError": true,
"exitCode": "ENOENT",
"stderr": "",
"stdoutPreview": ""
}Interpretasi: proses gagal bahkan sebelum command dijalankan. Biasanya path binary salah atau codex tidak ada di PATH proses.
Contoh kedua: token tidak tersedia di worker.
{
"event": "codex_exec",
"cwd": "/var/www/myapp",
"durationMs": 230,
"hasError": true,
"exitCode": 1,
"stderr": "authentication failed: missing environment variable",
"stdoutPreview": ""
}Interpretasi: binary ditemukan, tetapi ENV yang diperlukan tidak diteruskan.
Contoh ketiga: working directory salah.
{
"event": "codex_exec",
"cwd": "/",
"durationMs": 55,
"hasError": true,
"exitCode": 1,
"stderr": "config file not found",
"stdoutPreview": ""
}Interpretasi: command berjalan, tetapi dari direktori yang tidak sesuai.
Perbaikan yang Aman dan Direkomendasikan
Gunakan absolute path ke binary
Jika lokasi binary stabil, lebih aman memanggilnya dengan path absolut daripada mengandalkan PATH runtime. Ini mengurangi variasi antar environment.
Kelebihan: lebih deterministik.
Kekurangan: perlu disesuaikan saat deploy jika lokasi binary berubah.
Tetapkan environment secara eksplisit
Jangan bergantung pada shell profile interaktif. Untuk service, queue, atau worker, deklarasikan environment yang dibutuhkan di mekanisme yang memang mengelola proses tersebut, lalu restart worker jika perlu agar perubahan terbaca.
Kelebihan: perilaku lebih konsisten.
Kekurangan: konfigurasi awal sedikit lebih panjang.
Tetapkan cwd eksplisit
Selalu set current working directory ke root proyek atau direktori kerja yang memang dibutuhkan command. Ini penting terutama jika Codex CLI bergantung pada file lokal atau konteks repository.
Jangan sembunyikan stderr
Jika ada satu perbaikan yang langsung menaikkan kualitas debugging, ini dia. Simpan stderr ke structured log dengan pembatas ukuran. Jangan tampilkan detail sensitif ke response client, tetapi jangan hilangkan dari log internal.
Pisahkan eksekusi berat ke queue
Jika proses Codex CLI bisa lama, hindari menjalankannya di jalur request sinkron. Gunakan queue/job dan kembalikan status asinkron ke client.
Kapan dipilih? Saat durasi proses tidak bisa diprediksi ketat, atau ada risiko timeout gateway dan worker request.
Tambahkan timeout yang realistis dan fallback
Timeout tetap penting agar proses tidak menggantung. Namun timeout harus realistis sesuai karakter tugas. Jika timeout tercapai, kembalikan status yang jelas, tandai job gagal dengan alasan terstruktur, dan siapkan fallback yang aman.
Contoh Implementasi yang Lebih Tahan Error
Node.js / Express
const { execFile } = require('child_process');
function runCodex(args, options = {}) {
return new Promise((resolve, reject) => {
const child = execFile(
process.env.CODEX_BIN || '/usr/local/bin/codex',
args,
{
cwd: process.env.CODEX_CWD || '/var/www/myapp',
env: {
...process.env,
PATH: process.env.PATH || '/usr/local/bin:/usr/bin:/bin'
},
timeout: 120000,
maxBuffer: 1024 * 1024
},
(error, stdout, stderr) => {
if (error) {
error.stderr = stderr;
error.stdout = stdout;
return reject(error);
}
resolve({ stdout, stderr });
}
);
});
}Pola ini membantu karena konfigurasi binary, cwd, dan timeout terkonsolidasi di satu tempat.
Laravel / Queue Worker
use Symfony\Component\Process\Process;
use Illuminate\Support\Facades\Log;
$process = new Process([
env('CODEX_BIN', '/usr/local/bin/codex'),
'run',
'--json',
], base_path(), [
'PATH' => env('PATH_RUNTIME', '/usr/local/bin:/usr/bin:/bin'),
'HOME' => env('HOME_RUNTIME', base_path()),
] + $_ENV);
$process->setTimeout(120);
$process->run();
Log::info('codex_exec', [
'successful' => $process->isSuccessful(),
'exit_code' => $process->getExitCode(),
'stderr' => mb_substr($process->getErrorOutput(), 0, 4000),
]);
if (! $process->isSuccessful()) {
throw new \RuntimeException('Codex CLI failed');
}Yang penting dari contoh ini bukan framework tertentu, melainkan praktik berikut:
- binary path eksplisit,
base_path()sebagai working directory,- environment minimum yang dibutuhkan,
- stderr dicatat sebelum exception dilempar.
Checklist Verifikasi Sebelum Menyimpulkan Bug pada Codex CLI
- Apakah binary
codexbenar-benar ada di path yang dipakai backend? - Apakah backend menggunakan absolute path ke binary?
- Apakah user proses backend punya hak execute pada binary?
- Apakah worker atau service memiliki environment variable yang dibutuhkan?
- Apakah perubahan ENV sudah diikuti restart worker/service?
- Apakah
cwdsudah ditetapkan eksplisit? - Apakah path file input/output menggunakan path absolut?
- Apakah
stderrdan exit code sudah tercatat? - Apakah timeout request atau worker cukup realistis?
- Apakah command sudah diuji sebagai user yang sama dengan proses server?
Pencegahan agar Error 500 Tidak Berulang
1. Health check untuk dependency CLI
Buat endpoint internal atau startup check yang memverifikasi hal-hal minimum:
- binary Codex CLI tersedia,
- versi atau respons dasar bisa dibaca,
- working directory valid,
- environment wajib tersedia.
Tujuannya bukan menjalankan proses berat, tetapi mendeteksi salah konfigurasi sebelum request bisnis masuk.
2. Structured logging
Gunakan log JSON atau format terstruktur agar mudah dicari berdasarkan:
event,request_id,job_id,exit_code,duration_ms.
Dengan begitu, Anda bisa membedakan apakah kegagalan dominan terjadi karena ENOENT, auth, timeout, atau permission.
3. Fallback yang jelas
Jangan biarkan semua kegagalan eksternal berubah menjadi 500 generik. Minimal, petakan kegagalan menjadi status internal yang bisa ditindaklanjuti:
binary_not_foundmissing_envpermission_deniedtimeoutinvalid_working_directory
Untuk client, respons tetap bisa generik bila perlu. Tetapi secara internal, sistem harus tahu alasan sebenarnya.
4. Konfigurasi eksplisit per environment
Simpan lokasi binary, timeout, dan direktori kerja di konfigurasi aplikasi atau konfigurasi deployment, bukan tersebar di kode dan shell profile developer.
5. Uji dari konteks runtime nyata
Jangan hanya menguji dari terminal lokal. Tambahkan pengujian smoke dari proses yang benar-benar akan menjalankan command: worker, container, service, atau web process.
Kesalahan Umum yang Sering Membuat Debugging Lama
- Menganggap jika command sukses di laptop, berarti server pasti sama.
- Menggunakan
exec('codex ...')tanpa absolute path dan tanpa log stderr. - Menyimpan token di shell profile lalu lupa bahwa worker tidak membacanya.
- Tidak me-restart queue worker setelah mengubah environment.
- Menggunakan path relatif untuk file input/output.
- Menjalankan proses berat langsung di request HTTP sinkron.
- Mengembalikan 500 generik tanpa request ID atau log terstruktur.
Penutup
Dalam praktik integrasi Codex CLI pada backend, termasuk pola penggunaan yang sering dirujuk dari konteks bozhouDev/codex-orange-book, error HTTP 500 paling sering bukan berasal dari Codex CLI itu sendiri, melainkan dari perbedaan runtime antara terminal dan proses server. Dua penyebab terbesar adalah PATH yang berbeda dan ENV yang tidak terbaca, lalu disusul permission, working directory, timeout, dan logging yang kurang.
Jika Anda ingin mempercepat diagnosis, lakukan tiga hal ini terlebih dahulu: gunakan absolute path ke binary, tetapkan cwd dan environment secara eksplisit, lalu catat stderr beserta exit code. Dari sana, penyebab 500 biasanya jauh lebih cepat terlihat dan perbaikannya menjadi deterministik, bukan sekadar coba-coba.
Komentar
0 komentar
Masuk ke akun kamu untuk ikut berkomentar.
Belum ada komentar
Jadilah yang pertama ikut berdiskusi!