laravel/framework · error · InvalidArgumentException

Unknown visibility: {$visibility}.

Error message

Unknown visibility: {$visibility}.

What it means

Thrown by FilesystemAdapter::parseVisibility() when the visibility argument is not one of the FilesystemContract constants 'public' or 'private'. parseVisibility translates Laravel visibility strings to Flysystem Visibility enum values; any other value (typo, casing, numeric) is rejected because Flysystem has no concept for it.

Source

Thrown at src/Illuminate/Filesystem/FilesystemAdapter.php:1094

    /**
     * Parse the given visibility value.
     *
     * @param  string|null  $visibility
     * @return string|null
     *
     * @throws \InvalidArgumentException
     */
    protected function parseVisibility($visibility)
    {
        if (is_null($visibility)) {
            return;
        }

        return match ($visibility) {
            FilesystemContract::VISIBILITY_PUBLIC => Visibility::PUBLIC,
            FilesystemContract::VISIBILITY_PRIVATE => Visibility::PRIVATE,
            default => throw new InvalidArgumentException("Unknown visibility: {$visibility}."),
        };
    }

    /**
     * Define a custom callback that generates file download responses.
     *
     * @param  \Closure  $callback
     * @return void
     */
    public function serveUsing(Closure $callback)
    {
        $this->serveCallback = $callback;
    }

    /**
     * Define a custom temporary URL builder callback.
     *
     * @param  \Closure  $callback

View on GitHub (pinned to bd6b5437e6)

Solutions

  1. Pass only 'public' or 'private'.
  2. Normalize input: strtolower(trim($input)) and map to the two constants.
  3. Validate user-provided visibility against ['public','private'] before storage calls.
  4. For ACL-specific tuning, configure the disk's 'permissions' or 'options' arrays instead.

Example fix

// before - AWS-style ACL string is not a Laravel visibility
Storage::setVisibility('file.txt', 'public-read');

// after
Storage::setVisibility('file.txt', 'public');
Defensive patterns

Strategy: validation

Validate before calling

if (! in_array($visibility, ['public', 'private'], true)) {
    throw new \InvalidArgumentException('Visibility must be "public" or "private"');
}
Storage::setVisibility($path, $visibility);

Type guard

function isValidVisibility(?string $visibility): bool
{
    return in_array($visibility, ['public', 'private'], true);
}

Try / catch

try {
    Storage::setVisibility($path, $visibility);
} catch (\InvalidArgumentException $e) {
    if (str_contains($e->getMessage(), 'Unknown visibility')) {
        abort(422, 'Invalid visibility value');
    }
    throw $e;
}

Prevention

When it happens

Trigger: Calling Storage::disk($name)->setVisibility($path, $visibility) (or put() with a visibility option) where $visibility is not exactly 'public' or 'private' - e.g. 'PUBLIC', 'read-only', 'public-read', or an enum.

Common situations: Passing AWS ACL strings ('public-read', 'bucket-owner-full-control') instead of Laravel's visibility strings; user input fed straight into setVisibility; case mismatch from an uppercased env var.

Related errors


AI-assisted analysis of laravel/framework@bd6b5437e6 (2026-08-06). Data as JSON: /data/errors/c3ee33b97acafa11.json. Report an issue: GitHub.