This page covers the most common problems developers encounter while working on Exowpee, with practical solutions for each.

I got a 403 Forbidden

The system is telling you “I know who you are, but you are not allowed to do this.”

Check 1: Does the user’s profile have the required permission?

Look at the permissions array in the response. Is the required permission listed? For example, if you are trying to create a product, you need products.create.

Check 2: Is the policy checking the right thing?

Find the relevant Policy class (e.g., ProductPolicy) and check what permission it requires:
Make sure the permission name matches exactly — products.create is not the same as create_product.

Check 3: Is the company context correct?

Permissions are scoped per company. If the user switched profiles and the new profile does not have the required role, they will get a 403.

Check 4: Is this an agent trying to access a user-only endpoint?

IAM management endpoints (/v1/iam/*) require auth:api only. If an agent tries to access them, they get a 403.

I got a 422 Validation Error

The request data failed validation. The response body tells you exactly what is wrong.

Check 1: Read the error response

Each key in the errors object is the field that failed, and the value is an array of error messages.

Check 2: Find the FormRequest class

The validation rules are defined in the corresponding FormRequest. For POST /v1/order/orders, look at CreateOrderRequest:

Check 3: Check for authorization failures in FormRequest

If authorize() returns false, you get a 403, not a 422. But if the error message is vague, the authorize method might be the issue.

Data is not showing up

You created a record but it does not appear in queries.

Check 1: Are you in the right company context?

The most common cause. Data is scoped to the active company from the JWT token. If you created data in Company A but are now querying in Company B, you will not see it.

Check 2: Is the data organization-scoped or company-scoped?

Products are organization-scoped (shared across all companies). Orders are company-scoped (only visible in the company where they were created). If you are looking for a product, any company in the organization should see it. If you are looking for an order, you must be in the right company.

Check 3: Was the record soft-deleted?

Many models use soft deletes. The record exists in the database but has a deleted_at timestamp. Standard queries exclude soft-deleted records.

Check 4: Check pagination

The API uses cursor pagination. If you are not seeing all records, check if there is a next_cursor in the response — you may need to fetch the next page.

WebSocket events are not working

Clients are not receiving real-time updates.

Check 1: Is Laravel Reverb running?

Reverb must be running for WebSocket connections to work. Check the console output for errors.

Check 2: Is the queue worker running?

ClientRefresh and ResourceUpdated events run on the client_refresh queue. If the queue worker is not processing jobs, events will be queued but not broadcast.

Check 3: Is the client connecting to the right channel?

Private channels require the company ID:
If companyId is wrong or undefined, the client will connect to the wrong channel.

Check 4: Is channel authorization working?

Private channels require auth. Check routes/channels.php for the authorization logic.

Migration failed

Check 1: Is the database accessible?

Check 2: Does the migration have a dependency on another migration?

If a migration references a table that does not exist yet, it will fail. Check the migration order (timestamps in filenames).

Check 3: Is there a conflicting migration?

If someone else added a migration that modifies the same table, there may be a conflict. Check php artisan migrate:status to see which migrations have and have not run.

Check 4: Is the migration in the right package?

Package migrations are in packages/{Package}/database/migrations/. Make sure your migration is in the correct package directory.

Permission checks are not working

Check 1: Did you run permission discovery?

If a permission does not exist in the database, all checks for it will fail.

Check 2: Is the permission assigned to a role?

A permission existing is not enough — it must be assigned to a Role, which must be assigned to a Profile, which must be linked to the user via a UserProfile.

Check 3: Are you checking the Profile or the User?

Check 4: Is the guard correct?

Permissions are guard-scoped. A permission on the api guard will not be found when checking via the agent guard.

Tests are failing

Check 1: Is the test database set up?

Nothing to migrate by hand. --parallel creates and migrates <DB_DATABASE>_test_<N> for each process; add --recreate-databases to rebuild them:
Do not run php artisan migrate --env=testing inside the app container: env_file exports DB_DATABASE from .env, so it would migrate the development database.

Check 2: Are you running tests for the right package?

Check 3: Is there leftover state from a previous test?

If a test does not use RefreshDatabase or DatabaseTransactions, data from previous tests may leak through.

Using Telescope for debugging

Laravel Telescope is available in local development:
It is only active when APP_ENV=local.

What to look for

Clearing Telescope data

Configuration

Telescope config is in config/telescope.php:

Production debugging

Telescope is disabled in production. For production issues:
  1. Check application logs in storage/logs/
  2. Monitor failed jobs: php artisan queue:failed
  3. Use PostgreSQL query logging for database issues