phacility/phabricator · error · PhutilProxyException
Failed to JSON decode rule data!
Error message
Failed to JSON decode rule data!
What it means
Thrown by PhabricatorPolicyEditController while saving a custom policy from the policy edit dialog. The browser submits the whole rule list as a JSON string in the `rules` form field; when phutil_json_decode cannot parse it, the PhutilJSONParserException is rethrown wrapped in a PhutilProxyException with this message. It means the submitted payload is syntactically broken, before any rule semantics are examined.
Source
Thrown at src/applications/policy/controller/PhabricatorPolicyEditController.php:94
$policy = head($policies);
} else {
$policy = id(new PhabricatorPolicy())
->setRules(array($default_rule))
->setDefaultAction(PhabricatorPolicy::ACTION_DENY);
}
$root_id = celerity_generate_unique_node_id();
$default_action = $policy->getDefaultAction();
$rule_data = $policy->getRules();
$errors = array();
if ($request->isFormPost()) {
$data = $request->getStr('rules');
try {
$data = phutil_json_decode($data);
} catch (PhutilJSONParserException $ex) {
throw new PhutilProxyException(
pht('Failed to JSON decode rule data!'),
$ex);
}
$rule_data = array();
foreach ($data as $rule) {
$action = idx($rule, 'action');
switch ($action) {
case 'allow':
case 'deny':
break;
default:
throw new Exception(pht("Invalid action '%s'!", $action));
}
$rule_class = idx($rule, 'rule');
if (empty($rules[$rule_class])) {
throw new Exception(pht("Invalid rule class '%s'!", $rule_class));View on GitHub (pinned to 5720a38cfe)
Solutions
- Reproduce the save once in a normal browser session; if it works there, the failing client is sending malformed JSON.
- When scripting the endpoint, build the rules array in code and send json_encode($rules) as the field so it is guaranteed valid JSON.
- After an upgrade, clear the celerity cache and hard-refresh if the dialog itself submits garbage.
Example fix
// before: hand-typed field, trailing comma breaks JSON
rules=[{"action":"allow",}]
// after: JSON array of rule objects, string-encoded
rules=[{"action":"allow","rule":"PhabricatorProjectsPolicyRule","value":["PHID-PROJ-xxx"]}] Defensive patterns
Strategy: try-catch
Validate before calling
// Build the field in code so it is always valid JSON.
$rules = array(
array('action' => 'allow',
'rule' => 'PhabricatorProjectsPolicyRule',
'value' => array($project_phid)),
);
$post['rules'] = json_encode($rules); Try / catch
Wrap phutil_json_decode() in try { } catch (PhutilJSONParserException $ex) — the parser exception carries the failing byte offset. When rethrowing from a higher layer, wrap it as the controller does: throw new PhutilProxyException(pht('Failed to JSON decode rule data!'), $ex); so the low-level cause stays attached. Prevention
- Never hand-type the rules JSON; always json_encode a PHP array (or JSON.stringify in JS).
- Test the payload once in the browser dialog before automating the endpoint.
- Hard-refresh / clear celerity cache after upgrades so the dialog JS matches the server.
When it happens
Trigger: POSTing to the policy edit endpoint with a `rules` field that is not valid JSON: a hand-built curl payload, a request mangled by a proxy or browser extension, or stale celerity JS after an upgrade serializing the dialog incorrectly.
Common situations: Automating policy creation against the web endpoint instead of the UI, replaying and editing captured form posts, and half-upgraded installs serving a cached dialog bundle.
Related errors
- Configuration file is not properly formatted JSON. %s
- Expected JSON response from Duo.
- Unable to load file ("%s") for import.
- ERR-INVALID-AUTH
- Use form-encoded data to submit parameters to Conduit endpoi
AI-assisted analysis of phacility/phabricator@5720a38cfe (2026-08-21).
Data as JSON: /api/errors/d4f40630c1ae8a7a.
Report an issue: GitHub.