koel/koel · info

└── The podcast feed has not been updated recently, skipping

Error message

└── The podcast feed has not been updated recently, skipping.

What it means

An informational skip notice from `php artisan koel:podcasts:sync` (sequential mode, i.e. `--jobs=1` or a single podcast): `PodcastService::isPodcastObsolete()` returned false, so this podcast is deliberately not refreshed. 'Not obsolete' means either it was synced less than 12 hours ago (`last_synced_at`), or a HEAD request shows the feed's `Last-Modified` header is not newer than `last_synced_at` — i.e. the feed genuinely has no new content. This is healthy dedup behavior, not an error.

Source

Thrown at app/Console/Commands/SyncPodcastsCommand.php:49

            $this->info('No podcasts to sync.');

            return self::SUCCESS;
        }

        $jobs = (int) ($this->option('jobs') ?: config('koel.sync.podcast_jobs', 4));
        $jobs = min(max(1, $jobs), count($ids));

        return $jobs === 1 ? $this->syncSequentially() : $this->syncInParallel($ids, $jobs);
    }

    private function syncSequentially(): int
    {
        Podcast::query()->get()->each(function (Podcast $podcast): void {
            try {
                $this->info(sprintf('Checking "%s" for new content…', $podcast->title));

                if (!$this->podcastService->isPodcastObsolete($podcast)) {
                    $this->warn('└── The podcast feed has not been updated recently, skipping.');

                    return;
                }

                $this->info('└── Synchronizing episodes…');
                $this->podcastService->refreshPodcast($podcast);
            } catch (Throwable $e) {
                Log::error($e);
            }
        });

        return self::SUCCESS;
    }

    private function syncInParallel(array $ids, int $jobs): int
    {
        $this->info(sprintf('Syncing %d podcast(s) with %d parallel workers.', count($ids), $jobs));

View on GitHub (pinned to 41cab99fee)

Solutions

  1. No action needed if you just want new episodes — the feed has none since the last sync.
  2. To force a re-sync regardless, age out the freshness window: set `last_synced_at` back more than 12 hours (e.g. via tinker: `$podcast->update(['last_synced_at' => now()->subDay()])`) — though the Last-Modified check can still skip it if the feed is unchanged.
  3. Align your cron interval with the 12-hour window (or accept the skips) since the check exists to avoid hammering feed hosts.

Example fix

# before: sync skips the podcast
php artisan koel:podcasts:sync

# after: force re-check by aging the freshness window
php artisan tinker --execute="App\Models\Podcast::query()->update(['last_synced_at' => now()->subDay()]);"
php artisan koel:podcasts:sync
Defensive patterns

Strategy: validation

Validate before calling

// Predict the skip before running the command:
foreach (\App\Models\Podcast::all() as $podcast) {
    $fresh = abs($podcast->last_synced_at->diffInHours(now())) < 12;
    // $fresh === true ⇒ this podcast will print the skip notice
}

Prevention

When it happens

Trigger: Running `koel:podcasts:sync` twice within 12 hours; running it after 12+ hours when the feed's `Last-Modified` (RFC 1123) predates the last sync; a feed that omits `Last-Modified` would NOT hit this branch (missing header counts as obsolete and forces a sync).

Common situations: Cron schedules running podcast sync more frequently than the 12-hour freshness window (every sync in between just prints this); operators expecting a forced refresh; investigating why new episodes 'didn't sync' when in fact the feed hasn't changed.

Related errors


AI-assisted analysis of koel/koel@41cab99fee (2026-08-23). Data as JSON: /api/errors/4acbc83774390765. Report an issue: GitHub.