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 $callbackView on GitHub (pinned to bd6b5437e6)
Solutions
- Pass only 'public' or 'private'.
- Normalize input: strtolower(trim($input)) and map to the two constants.
- Validate user-provided visibility against ['public','private'] before storage calls.
- 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
- Only pass 'public' or 'private'.
- Normalize user input with strtolower() and validate against an allow-list.
- Map cloud ACLs to Laravel visibilities at the config level, not in calls.
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
- Database file at path [{$path}] does not exist. Ensure this
- This driver does not support retrieving URLs.
- Disk [{$name}] does not have a configured driver.
- Driver [{$driver}] is not supported.
- Scoped disk is missing "disk" configuration option.
AI-assisted analysis of laravel/framework@bd6b5437e6 (2026-08-06).
Data as JSON: /data/errors/c3ee33b97acafa11.json.
Report an issue: GitHub.