{"record":{"id":"bc0542f97287aad6","repo":"phacility/phabricator","slug":"invalid-json-input","errorCode":null,"errorMessage":"Invalid JSON input.","messagePattern":"Invalid JSON input\\.","errorType":"exception","errorClass":"PhutilProxyException","httpStatus":null,"severity":"error","filePath":"src/applications/conduit/ssh/ConduitSSHWorkflow.php","lineNumber":33,"sourceCode":"\n  public function execute(PhutilArgumentParser $args) {\n    $time_start = microtime(true);\n\n    $methodv = $args->getArg('method');\n    if (!$methodv) {\n      throw new Exception(pht('No Conduit method provided.'));\n    } else if (count($methodv) > 1) {\n      throw new Exception(pht('Too many Conduit methods provided.'));\n    }\n\n    $method = head($methodv);\n\n    $json = $this->readAllInput();\n    $raw_params = null;\n    try {\n      $raw_params = phutil_json_decode($json);\n    } catch (PhutilJSONParserException $ex) {\n      throw new PhutilProxyException(\n        pht('Invalid JSON input.'),\n        $ex);\n    }\n\n    $params = idx($raw_params, 'params', '[]');\n    $params = phutil_json_decode($params);\n    $metadata = idx($params, '__conduit__', array());\n    unset($params['__conduit__']);\n\n    $call = null;\n    $error_code = null;\n    $error_info = null;\n\n    try {\n      $call = new ConduitCall($method, $params);\n      $call->setUser($this->getSSHUser());\n\n      $result = $call->execute();","sourceCodeStart":15,"sourceCodeEnd":51,"githubUrl":"https://github.com/phacility/phabricator/blob/5720a38cfe95b00ca4be5016dd0d2f3195f4fa04/src/applications/conduit/ssh/ConduitSSHWorkflow.php#L15-L51","documentation":"The SSH conduit workflow reads all of stdin and decodes it with phutil_json_decode(); failure raises a PhutilProxyException wrapping the parser exception. The expected payload is a JSON object (typically {\"params\": \"<json-encoded params string>\"}), so both the outer document and the nested params string must be valid JSON.","triggerScenarios":"Piping empty or truncated input; sending raw unescaped JSON for params (missing the outer wrapper); shell heredocs where quoting strips the escaped inner quotes, leaving the document malformed.","commonSituations":"Nested double-encoding surprises: the outer stdin is JSON and the 'params' member is itself a JSON-encoded string; constructing that by hand with echo frequently breaks escaping.","solutions":["Build the payload with a JSON encoder, e.g. printf '%s' \"$(php -r 'echo json_encode([\"params\" => json_encode([\"ids\" => [1]])]);')\".","Validate the payload with a JSON linter (or jq .) before piping it.","Remember the minimal valid payload is {} (empty object) when you have no parameters."],"exampleFix":"# before (params not wrapped/escaped correctly)\n$ echo '{\"params\":{\"ids\":[1]}' | ssh -p 2222 vcs@phab.example.com conduit maniphest.task.search\n# after (outer JSON, params is a JSON string)\n$ echo '{\"params\":\"{\\\"constraints\\\":{\\\"ids\\\":[1]}}\"}' | ssh -p 2222 vcs@phab.example.com conduit maniphest.task.search","handlingStrategy":"validation","validationCode":"# Build the nested payload with encoders and validate it before piping.\nPAYLOAD=$(php -r 'echo json_encode([\"params\" => json_encode($argv[1])]);' \\\n  '\"{\\\\\"constraints\\\\\":{\\\\\"ids\\\\\":[1]}}\"')\necho \"$PAYLOAD\" | jq . > /dev/null   # decode check\nprintf '%s' \"$PAYLOAD\" | ssh -p 2222 vcs@phab.example.com conduit maniphest.task.search","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Never hand-escape the nested params string; use two passes of an encoder (json of a json string).","Pipe the payload through jq (or json.loads) as a smoke test before every run.","Use printf '%s' instead of echo -e to avoid backslash interpretation mangling escapes."],"tags":["conduit","ssh","json","phabricator","php"],"backgroundTag":"json-parse-error","analyzedSha":"5720a38cfe95b00ca4be5016dd0d2f3195f4fa04","analyzedAt":"2026-08-21T05:07:25.672Z","schemaVersion":2},"datasetVersion":"2026-08-21T11:28:35.574Z"}