coollabsio/coolify · warning · Exception

Preview not found

Error message

Preview not found

What it means

save_preview() looks up a PR preview by id inside $this->application->previews before saving its domains. A null result - the preview was deleted, rolled back, or the id comes from stale browser state - throws before any FQDN validation or update runs.

Source

Thrown at app/Livewire/Project/Application/Previews.php:113

    public function confirmDomainUsage()
    {
        $this->forceSaveDomains = true;
        $this->showDomainConflictModal = false;
        if ($this->pendingPreviewId) {
            $this->save_preview($this->pendingPreviewId);
            $this->pendingPreviewId = null;
        }
    }

    public function save_preview($preview_id)
    {
        try {
            $this->authorize('update', $this->application);
            $success = true;
            $preview = $this->application->previews->find($preview_id);

            if (! $preview) {
                throw new \Exception('Preview not found');
            }

            // Find the key for this preview in the collection
            $previewKey = $this->application->previews->search(function ($item) use ($preview_id) {
                return $item->id == $preview_id;
            });

            if ($previewKey !== false && isset($this->previewFqdns[$previewKey])) {
                $this->validate([
                    "previewFqdns.{$previewKey}" => ValidationPatterns::applicationDomainRules(),
                ]);

                $fqdn = $this->previewFqdns[$previewKey];

                if (! empty($fqdn)) {
                    $fqdn = ValidationPatterns::normalizeApplicationDomains($fqdn);
                    $this->previewFqdns[$previewKey] = $fqdn;

View on GitHub (pinned to 70b9acc424)

Solutions

  1. Refresh the previews panel so it lists only live previews
  2. Confirm the preview still exists (application > Previews / pull requests) before editing its domains
  3. Close duplicate tabs editing the same preview

Example fix

// before
$preview = $this->application->previews->find($preview_id);
if (! $preview) {
    throw new \Exception('Preview not found');
}
// after
$preview = $this->application->previews->find($preview_id);
if (! $preview) {
    $this->dispatch('error', 'This preview no longer exists. Refresh the list.');
    return;
}
Defensive patterns

Strategy: validation

Validate before calling

// before saving, confirm the preview still exists for this application
if (! $this->application->previews()->whereKey($previewId)->exists()) {
    $this->dispatch('error', 'Preview no longer exists - refresh the list.');
    return;
}

Type guard

function previewBelongsToApplication($application, int|string $previewId): bool
{
    return $application->previews()->whereKey($previewId)->exists();
}

Prevention

When it happens

Trigger: Calling save_preview with a preview_id that is not in the application's previews relation: the preview deployment was deleted in another tab, the PR was closed and cleaned up, or the browser table row is stale.

Common situations: Long-open preview panels; concurrent users closing previews; Livewire table state surviving preview deletion; re-submitting an edit form after the preview was destroyed.

Related errors


AI-assisted analysis of coollabsio/coolify@70b9acc424 (2026-08-17). Data as JSON: /api/errors/cc3bfdd440e7c71a. Report an issue: GitHub.