{"record":{"id":"7b324e2714c0394a","repo":"phacility/phabricator","slug":"use-form-encoded-data-to-submit-parameters-to-cond","errorCode":null,"errorMessage":"Use form-encoded data to submit parameters to Conduit endpoints. Sending a JSON-encoded body and setting 'Content-Type': 'application/json' is not currently supported.","messagePattern":"Use form-encoded data to submit parameters to Conduit endpoints\\. Sending a JSON-encoded body and setting 'Content-Type': 'application/json' is not currently supported\\.","errorType":"validation","errorClass":"Exception","httpStatus":null,"severity":"error","filePath":"src/applications/conduit/controller/PhabricatorConduitAPIController.php","lineNumber":634,"sourceCode":"      $value = $json->encodeFormatted($value);\n    }\n\n    $value = phutil_tag(\n      'pre',\n      array('style' => 'white-space: pre-wrap;'),\n      $value);\n\n    return $value;\n  }\n\n  private function decodeConduitParams(\n    AphrontRequest $request,\n    $method) {\n\n    $content_type = $request->getHTTPHeader('Content-Type');\n\n    if ($content_type == 'application/json') {\n      throw new Exception(\n        pht('Use form-encoded data to submit parameters to Conduit endpoints. '.\n            'Sending a JSON-encoded body and setting \\'Content-Type\\': '.\n            '\\'application/json\\' is not currently supported.'));\n    }\n\n    // Look for parameters from the Conduit API Console, which are encoded\n    // as HTTP POST parameters in an array, e.g.:\n    //\n    //   params[name]=value&params[name2]=value2\n    //\n    // The fields are individually JSON encoded, since we require users to\n    // enter JSON so that we avoid type ambiguity.\n\n    $params = $request->getArr('params', null);\n    if ($params !== null) {\n      foreach ($params as $key => $value) {\n        if ($value == '') {\n          // Interpret empty string null (e.g., the user didn't type anything","sourceCodeStart":616,"sourceCodeEnd":652,"githubUrl":"https://github.com/phacility/phabricator/blob/5720a38cfe95b00ca4be5016dd0d2f3195f4fa04/src/applications/conduit/controller/PhabricatorConduitAPIController.php#L616-L652","documentation":"decodeConduitParams() in PhabricatorConduitAPIController inspects the Content-Type header of requests to /api/ endpoints and hard-rejects 'application/json'. The Conduit HTTP protocol expects parameters as form fields (notably a 'params' field containing a JSON-encoded dictionary), so a raw JSON document body cannot be parsed and is rejected up front.","triggerScenarios":"Python requests.post(url, json={...}) which sets Content-Type: application/json; JS fetch with body JSON.stringify(...) and a JSON content-type header; curl -H 'Content-Type: application/json' -d '{...}'.","commonSituations":"Writing a new API client by analogy with ordinary REST APIs where JSON bodies are standard; HTTP wrapper libraries that silently switch to JSON serialization; porting integrations from systems that accept both encodings.","solutions":["Send the request as application/x-www-form-urlencoded with the whole parameter dictionary JSON-encoded into a single 'params' form field.","Add an 'output': 'json' form field if you want a JSON response.","Prefer arc call-conduit or the SSH conduit interface, which handle encoding for you."],"exampleFix":"# before\nimport requests\nrequests.post(endpoint, json={'constraints': {'ids': [1]}})\n# after\nimport json, requests\nrequests.post(endpoint, data={\n    'params': json.dumps({'constraints': {'ids': [1]}}),\n    'output': 'json',\n})","handlingStrategy":"validation","validationCode":"# Python: assert the encoding contract before sending.\nimport json, requests\n\ndef conduit_call(endpoint, token, method, params):\n    body = {\n        'params': json.dumps(params),   # whole dict JSON-encoded, form field\n        'output': 'json',\n    }\n    r = requests.post(endpoint + method, data=body,\n                      headers={'Content-Type': 'application/x-www-form-urlencoded'})\n    r.raise_for_status()\n    return json.loads(r.text)['result']","typeGuard":null,"tryCatchPattern":"# Check the response body rather than HTTP status: Conduit signals errors in JSON.\nresp = requests.post(url, data=body)\npayload = resp.json()\nif payload.get('error_code') == 'ERR-INVALID-AUTH':\n    ...  # token/header problem\nif not payload.get('error_code') is None:\n    raise RuntimeError(payload['error_info'])","preventionTips":["Never pass json= to requests or set a JSON Content-Type against /api/ endpoints.","Centralize request building in one helper so every call uses form encoding consistently.","Smoke-test a known method (user.whoami) when bringing up a new client to catch encoding mistakes early."],"tags":["conduit","http","content-type","json","phabricator"],"backgroundTag":"unsupported-content-type","analyzedSha":"5720a38cfe95b00ca4be5016dd0d2f3195f4fa04","analyzedAt":"2026-08-21T05:07:25.672Z","schemaVersion":2},"datasetVersion":"2026-08-21T11:28:35.574Z"}