Leantime/leantime · info · RuntimeException

Plugin %s is not enabled

Error message

Plugin %s is not enabled

What it means

This is an informational skip message from the maintenance command behind orphaned-file cleanup (app/Command/CleanupOrphanedFilesCommand.php:102). While iterating user-uploaded files in storage, the command computes `time() - $storage->lastModified($file)` and refuses to delete anything younger than 86400 seconds (24 hours). The warn() output is expected, protective behavior: young files are given a grace period because they may still be referenced by an in-flight upload, an unsaved editor session, or a queue job that has not linked them to their parent entity yet.

Source

Thrown at app/Command/DisablePluginCommand.php:42

    protected function configure(): void
    {
        $this->addArgument('plugin', InputArgument::REQUIRED, 'The plugin name');
    }

    /**
     * {@inheritdoc}
     */
    protected function executeCommand(): int
    {
        $name = $this->input->getArgument('plugin');
        $plugin = $this->getPlugin($name);

        if (! isset($plugin->id)) {
            throw new RuntimeException(sprintf('Plugin %s is not installed', $plugin->name));
        }

        if (! $plugin->enabled) {
            throw new RuntimeException(sprintf('Plugin %s is not enabled', $plugin->name));
        }

        if (! $this->confirm(sprintf('Disable plugin %s', $plugin->name))) {
            return Command::SUCCESS;
        }

        return $this->plugins->disablePlugin($plugin->id) ? Command::SUCCESS : Command::FAILURE;
    }
}

View on GitHub (pinned to 9a9f49f100)

Solutions

  1. Treat the message as success, not failure: the file WILL be eligible for deletion once it is older than 24 hours — simply wait and let the next scheduled run process it.
  2. If you must verify deletion logic now, test against a file whose mtime you age manually: `touch -d '2 days ago' storage/app/uploads/<file>` then re-run the command.
  3. Confirm you are not accidentally running in --dry-run mode, which reports the same skip for young files while never deleting anything.
  4. If the skip list never shrinks day over day, check clock synchronization (NTP) between the app server and the storage/NFS/S3 volume so lastModified() is not in the future.
  5. Only if you fully understand the concurrency risk, adjust the hardcoded 86400 threshold in the command to a smaller window and redeploy.

Example fix

// before — hard-coded 24h grace period, constant buried in the condition
if ($fileAge < 86400) { // 24 hours
    $this->warn("Skipping {$file} - file is less than 24 hours old");
    continue;
}

// after — configurable grace period via LEAN_* env (exposed in config/.env.sample)
$gracePeriod = (int) (config('lean.file_cleanup_grace_seconds') ?: 86400);
if ($fileAge < $gracePeriod) {
    $this->warn("Skipping {$file} - file is less than " . intdiv($gracePeriod, 3600) . " hours old");
    continue;
}
Defensive patterns

Strategy: validation

Validate before calling

// Before running the cleanup for real, validate which files are actually eligible (>24h old)
use Illuminate\Support\Facades\Storage;
$storage = Storage::disk('local'); // same disk the command iterates
foreach ($storage->allFiles('uploads') as $file) {
    $eligible = (time() - $storage->lastModified($file)) >= 86400;
    if ($eligible) { /* will be considered for deletion on this run */ }
}

// And run the command's own dry-run first to preview behavior
// php bin/leantime files:cleanup-orphaned --dry-run

Prevention

When it happens

Trigger: Running the cleanup command (or its scheduled/cron invocation) shortly after users uploaded attachments, avatars, or file uploads from the Files domain/TinyMCE/Uppy flows; running it twice in a row on the same day (the second run re-encounters the same young files); running with --dry-run while validating which files would be removed; a file whose lastModified timestamp lies in the future due to clock skew on the storage volume (fileAge goes negative, still < 86400, so it is skipped).

Common situations: Operators seeing 'Skipping ...' lines in scheduled-task logs and mistaking them for failures; CI or Docker environments where storage/ is freshly seeded so every file appears young; testing cleanup behavior in a staging copy where all file mtimes were reset by the copy; expecting immediate reclamation of disk space after deleting tickets/comments.

Related errors


AI-assisted analysis of Leantime/leantime@9a9f49f100 (2026-08-21). Data as JSON: /api/errors/f804b81f4818e835. Report an issue: GitHub.