You’re reading the v0.1 development preview. APIs may change.
~ 5 min readUpdated 2026-10-29

Troubleshooting Elang

Start with the exact command or URL that failed. Note the HTTP status, your PHP version, and the last action you took. A small reproducible problem is easier to solve than changing several settings at once.

PHP or Composer is not recognized

Reopen your terminal after installing either tool. Run where.exe php on Windows, or command -v php on macOS and Linux. If the result points to an old installation, fix PATH rather than editing Elang's requirements.

Run php -v and composer --version. Elang requires PHP 8.3+ within PHP 8.x and Composer 2. Follow the environment lesson if either command is unavailable.

Composer reports a missing extension

Run php --ini to find the CLI configuration, then php -m to inspect loaded modules. Enable or install the named extension for the PHP version Composer actually uses.

Do not use --ignore-platform-reqs to hide the problem. That can produce an installation that fails at runtime. Installing an extension for PHP-FPM does not necessarily enable it for CLI PHP, or the other way around.

vendor/autoload.php is missing

Change into the directory containing your application's composer.json, then run:

composer install

Wait for the command to finish successfully. The vendor/ directory is generated by Composer and intentionally omitted from the downloadable source and Git repository.

Application key is missing or invalid

Run php elang key:generate from the application directory. Doctor should then report a valid encryption key.

The key must be a base64-encoded 32-byte value. Keep .env private. Do not replace a valid production key merely to troubleshoot an unrelated error: old ciphertext depends on that key. The generator refuses to replace a nonempty key without --force.

Database connection fails

Run php elang doctor. For SQLite, check that pdo_sqlite is enabled and that the database's parent directory is writable. For MySQL or PostgreSQL, check the matching PDO driver, server availability, database name, and credentials.

URL-encode special characters in connection credentials. Never paste a real connection URL into a public issue. Doctor hides credentials in its output.

No such table or table does not exist

A connection can work even when your schema has not been created. Run:

php elang migrate:status
php elang migrate

In production, review the pending migration files and use --force only after preparing a backup. If you changed DATABASE_URL, you may now be looking at a different database from the one you migrated.

A route returns 404

Run php elang routes. Compare the method and path with your request. A parameter requirement such as [0-9]+ intentionally rejects /posts/hello.

If / works but other pages fail on a web server, verify the document root and the rewrite rule. Apache needs the included .htaccess to be honored; Nginx needs a try_files rule that reaches index.php.

A 404 means the requested resource was not found. It should not be fixed by changing every missing page into a 200 response.

A request returns 405

The path exists, but the HTTP method does not match. A POST form needs a POST route. Check the Allow response header and the route list. A browser address bar sends GET, so it cannot directly exercise a POST-only endpoint.

A form returns 419

The CSRF token is missing, expired, or from another session. Open the form again and submit the newly rendered token. Confirm that SessionMiddleware runs before CsrfMiddleware, that the form includes _token, and that the browser accepts the session cookie.

When using fetch with cookies across origins, origin and cookie rules matter. Start with a same-origin form while learning. CSRF does not replace login or authorization.

An API returns 400, 415, or 422

  • 400: JSON could not be parsed, a parameter has an invalid shape, or the request structure is wrong.
  • 415: The endpoint expects Content-Type: application/json.
  • 422: Parsing succeeded, but a field failed validation. Read the errors object rather than guessing which field failed.

Use the validation example to see the difference with concrete requests.

A request returns 429

The API rate limit was reached. Wait for the Retry-After period. During testing, repeated calls from the same detected IP share a counter. Reverse-proxy client IP handling must be configured deliberately; do not blindly trust arbitrary forwarded headers.

A page returns 500

Find the request ID in the response and inspect storage/logs/app.log on the server. Production responses hide internal exception messages. Look for a missing binding, a template variable, a connection error, or a file permission failure near that request ID.

Reproduce the issue locally. Share a minimal example and sanitized log context, not credentials, private user data, or the entire production environment file.

Changes are not visible

Check that you edited the application being served, not a different checkout. Twig's source reload is enabled. The official website versions CSS and JavaScript URLs from file modification times.

For your own assets, change their version or filename when deploying updates. If you use PHP OPcache with timestamp checks disabled, deployment must reload the appropriate PHP workers. Do not reset unrelated services blindly.

Still stuck

Read the debugging lesson. A useful issue includes the framework revision, PHP version, command or request, expected result, actual result, and a small reproduction. The glossary explains the terms used in error discussions.

Need a hand?

Check the troubleshooting guide, look up a term in the glossary, or work through the complete task board project.

Search Elang documentation

Start typing to find your next step.