ratchetphp/Ratchet · error · UnexpectedValueException

Invalid site control set

Error message

Invalid site control set

What it means

FlashPolicy::setSiteControl() defines the <site-control permitted-cross-domain-policies="..."/> directive of the generated policy document. It validates the value via validateSiteControl() and throws UnexpectedValueException('Invalid site control set') for anything outside the Flash spec's accepted values. Only a fixed set of directives is legal: 'all', 'none', 'master-only', 'by-content-type', and 'by-ftp-filename'.

Solutions

  1. Use one of the five spec-valid values: 'all', 'none', 'master-only', 'by-content-type', 'by-ftp-filename'.
  2. If the intent is to restrict which domains may connect, do not change site-control — call addAllowedAccess() for each permitted domain instead.
  3. Whitelist/normalize the value in your config layer (strtolower plus in_array check) before passing it to setSiteControl.
  4. If unsure, omit setSiteControl; the default 'all' (permitted cross-domain policies everywhere) is applied by the constructor.

Example fix

// before
$fp->setSiteControl('allow-all');

// after
$fp->setSiteControl('all'); // or 'master-only', 'none', 'by-content-type', 'by-ftp-filename'
Defensive patterns

Strategy: validation

Validate before calling

$allowed = ['all', 'none', 'master-only', 'by-content-type', 'by-ftp-filename'];
$value = strtolower(trim($permittedCrossDomainPolicies));
if (!in_array($value, $allowed, true)) {
    throw new \InvalidArgumentException("permitted-cross-domain-policies must be one of: " . implode(', ', $allowed));
}
$fp->setSiteControl($value);

Type guard

function isValidSiteControl($v): bool {
    return in_array($v, ['all','none','master-only','by-content-type','by-ftp-filename'], true);
}

Try / catch

try {
    $fp->setSiteControl($directive);
} catch (\UnexpectedValueException $e) {
    if ($e->getMessage() === 'Invalid site control set') {
        error_log("Invalid permitted-cross-domain-policies directive: {$directive}");
    } else { throw $e; }
}

Prevention

When it happens

Trigger: Passing an arbitrary string like 'always', 'true', 'allow', or a custom policy name; leaving a config value blank or misspelling one of the five valid directives (e.g. 'Master-Only' with different casing if the validator is case-sensitive); calling setSiteControl with user-supplied input without whitelisting.

Common situations: Misunderstanding site-control as an allow-list (it is not; allowed domains go to addAllowedAccess); copying a meta-policy value from a different spec; config drift where the environment variable for the directive contains an unsupported option.

Understand the failure class

Background: Invalid enum value errors: "Unknown type", "Invalid scope", "must be one of" — when a string is not on the library's allowed list — this error's family across 23 libraries.

Related errors


AI-assisted analysis of ratchetphp/Ratchet@e621c6c40b (2026-09-16). Data as JSON: /api/errors/aec3f0518b3a1675. Report an issue: GitHub.

Appendix: source

Thrown at src/Ratchet/Server/FlashPolicy.php:98

    public function clearAllowedAccess() {
        $this->_access      = array();
        $this->_cacheValid = false;

        return $this;
    }

    /**
     * site-control defines the meta-policy for the current domain. A meta-policy specifies acceptable
     * domain policy files other than the master policy file located in the target domain's root and named
     * crossdomain.xml.
     *
     * @param string $permittedCrossDomainPolicies
     * @throws \UnexpectedValueException
     * @return FlashPolicy
     */
    public function setSiteControl($permittedCrossDomainPolicies = 'all') {
        if (!$this->validateSiteControl($permittedCrossDomainPolicies)) {
            throw new \UnexpectedValueException('Invalid site control set');
        }

        $this->_siteControl = $permittedCrossDomainPolicies;
        $this->_cacheValid  = false;

        return $this;
    }

    /**
     * {@inheritdoc}
     */
    public function onOpen(ConnectionInterface $conn) {
    }

    /**
     * {@inheritdoc}
     */
    public function onMessage(ConnectionInterface $from, $msg) {

View on GitHub (pinned to e621c6c40b)