Troubleshooting


Use this page when something breaks during install, first login, publishing, or frontend builds. Each entry starts with the thing you are likely to see, then gives the shortest useful fix.
Deeper runbooks:
| Area | Runbook |
|---|---|
| Package discovery | Debugging package discovery |
| Admin extensions | Debugging admin extensions |
| Public output | Debugging public output |
| Marketplace | Debugging Marketplace |
Start with the symptom you can see:
| Symptom | Start here |
|---|---|
| Browser installation times out | Browser install timeout |
| An install or other job remains queued | Queue worker |
| Scheduled work never runs | Scheduler |
| You need the useful error rather than the UI | Installation logs |
Install and hosting
Section titled “Install and hosting”Health summary reports missing sites, languages, theme and admin access
Section titled “Health summary reports missing sites, languages, theme and admin access”If Composer installed the theme and its dependencies but the health summary says No sites found; No languages found, check the numbered install log for Install Capell Admin, Set up Capell Admin, and Install Capell Frontend. Composer availability alone does not establish that these lifecycles ran. The installer expands downloaded theme dependencies into the remaining plan, prepares their required host patches, and creates the Filament panel before Admin setup.
To recover an interrupted installation, rerun php artisan capell:install, keep Capell Admin and Capell Frontend selected, and reuse the existing administrator. Keep default content setup enabled. Do not use --fresh: it deletes existing data and is unnecessary for this recovery. Then run php artisan capell:doctor --install-summary --skip-package-doctors and build the frontend with npm run build.
Regression coverage must start with only capell-app/installer installed and discover Admin and Frontend during the theme download. A consumer that preinstalls every package, or tests using only vendor/* dependency fixtures, bypasses this path. The public release smoke workflow covers both starting states.
The browser installer times out during a step
Section titled “The browser installer times out during a step”The installer shows this exact message when the web server ends a long request:
The web server timed out before the installer could finish this step. Use the command installer from the terminal so long-running package setup is not limited by the browser request timeout.Why: PHP, PHP-FPM, a proxy, or the hosting platform stopped the request before Composer, migrations, package setup, or the frontend build completed.
Fix: Use the CLI installer from the application directory. Increasing a public web timeout is not required when installation can run safely during deployment:
php artisan capell:installReopening the browser installer resumes from the last completed step. If a step genuinely exhausts the host’s available memory, report that step as a defect so it can be isolated or batched; changing PHP’s configured memory limit is not a Capell installation requirement.
You should see: The installer resumes at the interrupted step and finishes with the Capell health summary or a specific actionable failure.
A queued install or task never starts
Section titled “A queued install or task never starts”Why: QUEUE_CONNECTION=database, redis, or another asynchronous connection stores work for a separate queue worker. A browser request does not process that work itself.
Check:
php artisan config:show queue.defaultphp artisan queue:failedphp artisan queue:workqueue:work is a useful immediate check. In production, configure the host’s process manager to keep the worker running and restart workers during deployment with php artisan queue:restart. If the database queue is selected but its table is missing, run php artisan queue:table && php artisan migrate once.
You should see: Queued installation, publishing, cache, notification, and package jobs move from pending to completed. Retry a known safe failed job with php artisan queue:retry <job-id> only after fixing its reported cause.
Scheduled Capell tasks never run
Section titled “Scheduled Capell tasks never run”Why: Laravel’s scheduler and its queue workers are separate processes. A queue worker cannot trigger scheduled commands, and the scheduler does not replace a worker for commands that dispatch jobs.
Check the registered schedule:
php artisan schedule:listIn production, configure one cron or hosting-panel scheduled task to run Laravel every minute. Replace the example path with the application release path:
* * * * * cd /path/to/application && php artisan schedule:run >> /dev/null 2>&1You should see: php artisan schedule:list shows the next run times and the scheduled commands begin running. Site Health keeps this check amber because Capell cannot verify a recent scheduler heartbeat from local state; use it as an operational reminder.
Find the installation error and logs
Section titled “Find the installation error and logs”Start with the browser installer’s Download log report. It records the environment, preflight checks, selected plan, progress lines, and safe remediation text.
The step-by-step browser installer also writes storage/logs/capell-install-<install-id>.log. Find recent install logs with:
find storage/logs -name 'capell-install-*.log' -type f -printLaravel exceptions normally appear in storage/logs/laravel.log. Capell frontend diagnostics use storage/logs/capell.log when the capell Monolog channel is configured. A fatal memory error or web timeout can happen before Laravel writes either file, so also inspect the host’s PHP-FPM, Apache, Nginx, or platform error log.
Do not publish complete logs without reviewing them for paths, environment values, URLs, email addresses, tokens, or other customer data.
php artisan says permission denied
Section titled “php artisan says permission denied”When it happens: You cloned the project, copied files from another machine, or unpacked a deployment artifact.
Run:
chmod +x artisanchmod -R u+rwX storage bootstrap/cacheYou should see: php artisan about prints the Laravel environment summary.
composer require capell-app/installer cannot find the package
Section titled “composer require capell-app/installer cannot find the package”Why: Composer cannot resolve the package from Packagist. The foundation packages are public and need no credentials, so the usual causes are a stale Composer cache, a custom repositories entry shadowing Packagist, or a PHP platform requirement the application does not meet.
Check:
composer config repositoriescomposer show capell-app/installer --availableConfirm the package name is spelled capell-app/installer, that no custom repository entry overrides Packagist, and that the application meets the install requirements. Then run:
composer clear-cachecomposer require capell-app/installerYou should see: Composer resolves capell-app/installer and its capell-app/core dependency. The admin and frontend packages are added later by php artisan capell:install.
Admin access
Section titled “Admin access”/admin returns 403 or will not let you log in
Section titled “/admin returns 403 or will not let you log in”Why: The user exists, but Filament access or Capell roles were not assigned.
Run:
php artisan optimize:clearReplace [email protected] with the admin user email.
You should see: The user can open /admin and reach the dashboard.
The dashboard loads, but Pages or Settings are missing
Section titled “The dashboard loads, but Pages or Settings are missing”Why: Package resources, permissions, or Filament navigation were not registered.
Run:
php artisan optimize:clearphp artisan capell:admin-installYou should see: The sidebar includes Capell resources such as Pages, Media, and Settings.
Frontend and publishing
Section titled “Frontend and publishing”Published pages still show old content
Section titled “Published pages still show old content”Why: You are looking at cached static HTML from the installed cache/static package.
Run:
php artisan capell:html-cache:clearOnly run commands that exist in the installed package set. Check with php artisan list capell. If capell-app/html-cache is installed, also run php artisan capell:static-site to rebuild generated public HTML.
If your queue is not sync, keep a worker running:
php artisan queue:workYou should see: The frontend updates after refresh.
Published pages never generate
Section titled “Published pages never generate”Why: The installed cache/static package dispatches static HTML generation through Laravel queues.
For local development, set:
QUEUE_CONNECTION=syncFor database or Redis queues, run:
php artisan queue:workYou should see: New or changed pages appear in the cache package’s configured static artifact path.
The frontend shows Laravel’s default welcome page
Section titled “The frontend shows Laravel’s default welcome page”Why: The default / route is still taking priority.
Fix: Remove the default route from routes/web.php:
Route::get('/', function () { return view('welcome');});Then run:
php artisan optimize:clearYou should see: Capell handles the homepage route.
Can't resolve 'swiper/...' during npm run build
Section titled “Can't resolve 'swiper/...' during npm run build”Why: A symlinked package imports Swiper through an export path that your Tailwind/Vite setup cannot resolve.
Run:
php artisan capell:frontend-tailwind-assets --reportnpm installnpm run buildcapell:frontend-tailwind-assets is provided by capell-app/frontend; check php artisan list capell if the command is not present.
If it still fails, add Vite aliases as described in Tailwind vendor CSS.
You should see: Vite finishes without unresolved Swiper imports.
Tailwind misses Capell admin styles
Section titled “Tailwind misses Capell admin styles”Why: Your Filament theme is not scanning Capell’s Blade views.
Fix: Add the Capell sources from themes and frontend assets to resources/css/filament/admin/theme.css, then run:
npm run buildphp artisan optimize:clearYou should see: Capell admin fields, tables, and widgets render with the expected styling.
Installation failures
Section titled “Installation failures”Laravel\Prompts\Exceptions\NonInteractiveValidationException: Required.
Section titled “Laravel\Prompts\Exceptions\NonInteractiveValidationException: Required.”Why: A Capell command asked for interactive input while running in CI, Docker, or --no-interaction.
Fix: Pass every prompted decision as a flag. --user can select an account that already exists, but it does not create that account or set its login credentials:
For a fresh app with no users yet, supply the complete first-user and install decisions:
php artisan capell:install \ --no-interaction \ --url=https://example.com \ --package-mode=all \ --theme=default \ --name="Admin User" \ --password="change-this-password" \ --clear-cache \ --install-welcome-routeYou should see: The command either completes or prints the next missing option explicitly.
Browser installer reports Preflight checks failed.
Section titled “Browser installer reports Preflight checks failed.”Why: The /install browser flow runs InstallerPreflight before install steps. Blocking failures usually mean the web PHP runtime cannot do something the CLI can: load a required extension, run subprocesses, write to storage or bootstrap/cache, connect to the database, store cache state, or resolve selected Composer packages.
Check the installer report first. It includes the failed check key and remediation text. Then compare the configured binaries:
php artisan config:show capell-installer.php_binaryphp artisan config:show capell-installer.composer_binaryphp artisan config:show cache.defaultphp artisan config:show queue.defaultIf optional packages were selected, run the Composer checks from the same app:
composer show capell-app/filamentors --availablecomposer config repositoriesFix: Set CAPELL_SETUP_PHP_BINARY to CLI PHP, set CAPELL_SETUP_COMPOSER_BINARY when Composer is not on the web user’s path, fix permissions, or repair Composer repository/auth access. For a fresh app using database cache before migrations exist, temporarily use file cache or create the cache table before retrying.
You should see: The preflight status changes from fail to pass or warning, and the browser installer can advance to install steps.
Browser installer progress says the install session expired
Section titled “Browser installer progress says the install session expired”Why: The browser installer stores progress under cache keys named capell.install.{installId}.* and protects concurrent installs with capell.install.lock. If cache is cleared, a volatile cache store restarts, or the install takes longer than the lock TTL, the progress route no longer has enough state to continue.
Check:
php artisan config:show cache.defaultphp artisan config:show session.driverphp artisan optimize:clearIf this happened after a long queued install, check that a worker is running:
php artisan queue:workFix: Restart the browser installer. For repeat failures, use a persistent cache store, avoid clearing cache mid-install, and keep the queue worker alive. On local/dev only, clear the stale installer lock if you know no install job is running.
You should see: A new install ID and fresh progress page.
/install says Capell is already installed
Section titled “/install says Capell is already installed”Why: EnsureNotInstalled treats Capell as installed when the Admin package is installed, the sites table exists, and at least one site row exists. This protects real sites from exposing setup forms.
Check:
php artisan route:list --name=capell-installerphp artisan tinkerIn Tinker:
Capell\Installer\Support\InstallerInstallationState::capellIsInstalled();Fix: Use the admin panel for a normal installed app. For a controlled local reinstall only, set:
CAPELL_SETUP_ALLOW_REINSTALL=trueThen clear cached config:
php artisan config:clearYou should see: /install opens the setup form again only in that controlled environment.
capell:install --developer-tooling fails while cloning a Capell GitHub repository
Section titled “capell:install --developer-tooling fails while cloning a Capell GitHub repository”Why: The installer reached Composer, but Composer cannot access one of the configured Capell repositories. This is separate from installer option validation. It usually means the app is configured with private vcs repositories but the current machine does not have valid GitHub credentials, or local path repositories were removed from composer.json.
Check:
composer config repositoriescomposer show capell-app/access-gatecomposer show capell-app/agent-bridge --availableFor local Capell development, prefer path repositories for locally checked-out packages. For production or CI installs from VCS, make sure Composer auth can access the private repositories before running:
php artisan capell:install \ --no-interaction \ --url=https://example.com \ --all-packages \ --developer-toolingYou should see: Composer installs capell-app/agent-bridge and then the installer continues to package setup.
Marketplace
Section titled “Marketplace”Marketplace connect account fails or returns an invalid session
Section titled “Marketplace connect account fails or returns an invalid session”Why: Marketplace account linking creates a short-lived session, sends the admin to Capell App, then validates the returned state and code on the admin callback route. Failures usually come from a missing APP_URL host, a stale approval URL, expired session, wrong Marketplace API URL, or an admin session that is no longer authenticated.
Check config:
php artisan config:show app.urlphp artisan config:show capell-marketplace.marketplace.base_urlphp artisan route:list --name=capell-marketplaceCheck the latest account session:
select connection_session_id, claimed_domain, app_url, callback_url, status, expires_at, completed_at, last_errorfrom marketplace_account_connection_sessionsorder by id desclimit 5;Fix: Set APP_URL to a URL with a host, use https://capell.app/api/v1 unless you are intentionally testing another API, clear config cache, then start a new connection from the Marketplace page. Do not reuse old approval URLs after starting a newer connection.
You should see: A marketplace_instances row with an instance_id, account email, and last_heartbeat_at.
Marketplace catalogue loads but install is blocked
Section titled “Marketplace catalogue loads but install is blocked”Why: Browsing the catalogue only proves /extensions is reachable. Install authorization also needs the connected instance, licence/domain state, local compatibility checks, and any Marketplace policy required for that extension.
Check:
select instance_id, connection_mode, account_email, last_heartbeat_atfrom marketplace_instancesorder by last_heartbeat_at desclimit 5;Check the local package platform versions:
composer show capell-app/core filament/filament livewire/livewire laravel/frameworkFix: Connect a Capell account, resolve any diagnostics, activate or purchase the licence when requested, and follow the Marketplace action reason. If the browser looks stale during local debugging, clear local cache:
php artisan cache:clearYou should see: The Marketplace primary action changes to the next valid state, such as activate licence, install, installed, or incompatible with a clear reason.
Marketplace heartbeat or update check fails
Section titled “Marketplace heartbeat or update check fails”Why: PhoneHomeAction requires a Marketplace API URL, a public callback URL, a known instance ID, and network access to /instances/heartbeat.
Check:
php artisan config:show capell-marketplace.marketplace.base_urlphp artisan config:show app.urlphp artisan config:show capell-marketplace.marketplace.webhook_urlThen inspect local state:
select instance_id, last_heartbeat_atfrom marketplace_instancesorder by last_heartbeat_at desclimit 5;
select source, checked_at, capell_version, metadatafrom marketplace_update_advisory_snapshotsorder by checked_at desclimit 5;Fix: Connect the account if no instance exists. Set CAPELL_MARKETPLACE_WEBHOOK_URL when APP_URL is local, private, or not the URL Capell App should call. Confirm the server can reach the configured Marketplace API.
You should see: last_heartbeat_at updates and a new marketplace_update_advisory_snapshots row appears.
Runtime and data errors
Section titled “Runtime and data errors”TypeError: ... __PHP_Incomplete_Class returned from SiteLoader::languages()
Section titled “TypeError: ... __PHP_Incomplete_Class returned from SiteLoader::languages()”Why: Older Capell builds could read a cached Eloquent collection before the Language model was loaded.
Fix:
composer update capell-app/core -Wphp artisan optimize:clearphp artisan cache:clearYou should see: The second request after cache warmup works normally.
UrlMissingSiteDomainException: Site domain not found for page ID ...
Section titled “UrlMissingSiteDomainException: Site domain not found for page ID ...”When it happens: /admin or a Livewire admin update fails while rendering a page table, dashboard Filament widget, relation manager, or URL column. The stack usually ends in PageUrl::getFullUrlAttribute() after a table column calls $pageUrl->full_url.
Example trace:
Capell\Core\Models\PageUrl::getFullUrlAttribute()Illuminate\Database\Eloquent\Concerns\HasAttributesAwobaz\Compoships\ComposhipsCapell\Admin\Filament\Components\Tables\Columns\Page\PageNameColumnFilament\Tables\Columns\TextColumnLivewire\Mechanisms\HandleRequests\HandleRequests@handleUpdateWhy it occurs: PageUrl::siteDomain() is a composite relation. It matches page_urls.site_id and page_urls.language_id to site_domains.site_id and site_domains.language_id.
That relation cannot resolve if either of these is true:
- The data is incomplete: the
page_urlsrow points at a(site_id, language_id)pair with no matchingsite_domainsrow. - The model was under-selected: an eager load selected only columns like
idandurl, so Eloquent has aPageUrlinstance but not thesite_idandlanguage_idattributes needed by Compoships to build the relation query.
The second case is easy to spot in query logs. A broken lazy-load often looks like this:
select *from site_domainswhere site_domains.site_id is null and site_domains.site_id is not null and site_domains.language_id is not nulllimit 1;That contradictory site_id is null / site_id is not null condition means the relation was evaluated from a PageUrl model that did not have its composite key attributes loaded.
How this incident was traced: The failing stack pointed from PageUrl::getFullUrlAttribute() back to PageNameColumn::urlDescription(). That column rendered $page->pageUrl->full_url for the dashboard page list. The query log then showed Compoships trying to load siteDomain with site_id = null, which proved the accessor was not the source of the bad value; the admin rendering path was reaching full_url with a missing, incomplete, or non-renderable pageUrl relation.
How it was fixed: Admin display code now treats visit links as optional. PageNameColumn::urlDescription() resolves a renderable URL first:
- no persisted
pageUrl: do not render a link - under-selected
PageUrl: reload it withsiteDomain - no matching
siteDomain: do not render a link - valid
PageUrlandsiteDomain: render the short URL linked tofull_url
This keeps the admin panel available while preserving the stricter PageUrl::full_url behaviour for places where a real public URL must exist.
Check:
select id, pageable_id, site_id, language_id, urlfrom page_urlswhere pageable_id = 195 and pageable_type = 'page';
select id, site_id, language_id, scheme, domain, pathfrom site_domainswhere site_id = 4;Fix the data if needed: Add or repair the missing site_domains row for the page URL’s site and language. A page_urls row should not advertise a public URL for a site/language pair that cannot produce a host.
Fix the query if it was under-selected: Include every key used by downstream relations:
$query->select(['id', 'site_id', 'language_id', 'pageable_id', 'pageable_type', 'url']);Then eager-load siteDomain before rendering full_url:
$query->with('siteDomain');For page list surfaces, prefer loading enough relation data up front:
$query->with([ 'pageUrl.siteDomain', 'pageUrls' => fn ($query) => $query->with('siteDomain')->ordered(),]);Regression coverage: Keep a focused Livewire/Filament test that renders the affected admin surface with a page URL whose (site_id, language_id) has no matching site_domains row. The expected behaviour is that the table still renders the page and simply omits the broken visit link.
You should see: Admin tables and widgets render normally, and public/frontend URL generation still fails loudly if a real page URL has no matching domain.
Development and tests
Section titled “Development and tests”php artisan test fails with plugins table not found or RouteNotFoundException
Section titled “php artisan test fails with plugins table not found or RouteNotFoundException”Why: Tests booted routes before Capell migrations had created the expected tables.
Run:
php artisan migratephp artisan testIf this happens in package tests, update to the latest Capell 1.x packages and clear Testbench state:
composer update capell-app/core capell-app/admin capell-app/frontend -Wcomposer clearcomposer preparecomposer testYou should see: Routes register, and tests fail only on real assertions rather than missing install tables.
Maintaining this page
Section titled “Maintaining this page”Add a new troubleshooting entry
Section titled “Add a new troubleshooting entry”Use this shape:
- Put the exact error string in the heading.
- Explain the cause in plain language.
- Give the command or edit to make.
- Say what the user should see after the fix.
A completed install requests /resources/css/app.css and receives 404
Section titled “A completed install requests /resources/css/app.css and receives 404”Why: Installer theme metadata stores Vite source entry paths. Those entries must resolve through the build manifest; treating them as public files requests the unbuilt source path even after npm run build succeeds.
Fix: Use the release containing the theme metadata Vite resolver fix, install the frontend dependencies, and run npm run build. Verify that the homepage stylesheet URLs point into /build/assets/ and return HTTP 200. Public theme assets under vendor/ remain ordinary public files. The installer-only release smoke test checks linked local stylesheets as well as page responses.