{"record":{"id":"11f3f01410dfea6a","repo":"passbolt/passbolt_api","slug":"this-is-not-a-valid-ajax-json-request-11f3f0","errorCode":null,"errorMessage":"This is not a valid Ajax/Json request.","messagePattern":"This is not a valid Ajax/Json request\\.","errorType":"http","errorClass":"Cake\\Http\\Exception\\BadRequestException","httpStatus":400,"severity":"error","filePath":"plugins/PassboltCe/EmailNotificationSettings/src/Controller/NotificationOrgSettings/NotificationOrgSettingsPostController.php","lineNumber":71,"sourceCode":"\n        $msg = __('The notification settings for the organization were updated.');\n        $this->success($msg, $this->_formatForOutput($flatten));\n    }\n\n    /**\n     * Validate the request body\n     *\n     * @return array if the request body is valid\n     * @throws \\Cake\\Http\\Exception\\ForbiddenException If the user making request is not admin\n     * @throws \\Cake\\Http\\Exception\\BadRequestException If the request is not a Ajax/Json type\n     */\n    private function _validateRequestData(): array\n    {\n        if ($this->User->role() !== Role::ADMIN) {\n            throw new ForbiddenException(__('You are not allowed to access this location.'));\n        }\n        if (!$this->request->is('json')) {\n            throw new BadRequestException(__('This is not a valid Ajax/Json request.'));\n        }\n\n        $data = $this->request->getData();\n\n        foreach ($data as $key => $value) {\n            $data[$key] = QueryStringComponent::normalizeBoolean($value);\n        }\n\n        $form = new EmailNotificationSettingsForm();\n\n        if (!$form->validate($data)) {\n            $errors = $form->getErrors();\n\n            throw new CustomValidationException(__('The supplied email notification settings are not valid'), $errors);\n        }\n\n        $data = EmailNotificationSettingsForm::formatFormDataToOrgSettings($data);\n","sourceCodeStart":53,"sourceCodeEnd":89,"githubUrl":"https://github.com/passbolt/passbolt_api/blob/31c1bbc10f32808a607fa9bd81891e898779c0bc/plugins/PassboltCe/EmailNotificationSettings/src/Controller/NotificationOrgSettings/NotificationOrgSettingsPostController.php#L53-L89","documentation":"A BadRequestException thrown by NotificationOrgSettingsPostController::_validateRequestData when the request is not recognized as a JSON/Ajax request. Passbolt controllers of this style require the Accept header to indicate JSON so the request body can be parsed as JSON data.","triggerScenarios":"POST to /email-notification-settings/org-settings with role check passing but without 'application/json' in the Accept header (and not an XHR request), so $this->request->is('json') returns false.","commonSituations":"Calling the endpoint with curl or Postman with default Accept header (text/html, */*); form posts from plain HTML without X-Requested-With; integration scripts forgetting the Accept: application/json header.","solutions":["Add header 'Accept: application/json' to the request.","Send the payload with 'Content-Type: application/json' and a JSON body.","If using the passbolt JS SDK or an XHR client, keep the default XHR headers (X-Requested-With) intact.","Do not submit the endpoint via a plain HTML form post."],"exampleFix":"// before\ncurl -X POST -H 'X-Http-Token: <token>' -d 'settings=1' /email-notification-settings/org-settings\n\n// after\ncurl -X POST -H 'X-Http-Token: <token>' -H 'Content-Type: application/json' -H 'Accept: application/json' -d '{\"send_admin_user_setup_complete\":true}' /email-notification-settings/org-settings","handlingStrategy":"validation","validationCode":"if (stripos($acceptHeader, 'application/json') === false) {\n    throw new BadRequestException('Request must accept application/json');\n}","typeGuard":null,"tryCatchPattern":"try {\n    $response = $client->postEmailNotificationOrgSettings($data);\n} catch (BadRequestException $e) {\n    if (str_contains($e->getMessage(), 'Ajax/Json')) {\n        // add Accept: application/json / Content-Type: application/json and retry once\n    }\n}","preventionTips":["Always send 'Accept: application/json' and 'Content-Type: application/json' headers to passbolt JSON endpoints.","Use an HTTP client wrapper that sets JSON headers by default.","Avoid plain HTML form posts against JSON-only controllers.","In tests, use $this->postJson() / assert json type to mirror production calls."],"tags":["http","content-negotiation","json","bad-request"],"backgroundTag":"invalid-argument-format","analyzedSha":"31c1bbc10f32808a607fa9bd81891e898779c0bc","analyzedAt":"2026-09-17T00:04:38.960Z","contentChangedAt":"2026-09-17T00:04:38.960Z","schemaVersion":2},"datasetVersion":"2026-09-21T04:17:39.646Z"}