Getting 400 error when making AJAX call to WordPress admin-ajax.php

I’m having trouble with my WordPress AJAX implementation. When I try to send a request, I keep getting a 400 Bad Request error.

Error message I’m seeing:

POST http://localhost/.../wp-admin/admin-ajax.php 400 (Bad Request)

My JavaScript code:

$.ajax({
    type: "POST",
    url: ajax_vars.ajax_url,
    data: {
        action: 'create_new_password'
    },
    contentType: "application/json; charset=utf-8",
    dataType: "json",
    success: function(response) {
        var result = JSON.parse(response);
        $('#password_field').val(response);
        alert(JSON.parse(response));
    },
    error: function(xhr) {
        console.log(xhr);
    }
}).fail(function() {
    console.log("request failed");
});

PHP handler code:

add_action('admin_enqueue_scripts', 'load_custom_scripts');
function load_custom_scripts() {
    wp_register_script('password-handler', $plugin_url . 'js/password-handler.js', array('jquery'), '1.0.0', true);
    wp_enqueue_script(array('password-handler'));
    $variables = array('ajax_url' => admin_url('admin-ajax.php'));
    wp_localize_script('password-handler', 'ajax_vars', $variables);
}

add_action('wp_ajax_create_new_password', 'handle_password_creation');
function handle_password_creation() {
    $new_password = (string)wp_generate_password(8, true, false);
    echo $new_password;
    header('Content-Type: application/json');
    $output = json_encode($new_password);
    echo $output;
    exit;
}

I’ve looked at other similar posts but none of the suggested fixes worked for me. I’m pretty new to WordPress development so I might be missing something obvious. Any help would be appreciated!

Your success callback is parsing the response twice - that’s what’s breaking it. Since you set dataType: "json", jQuery already parses the JSON automatically. Remove var result = JSON.parse(response); and just use response directly. Your PHP is also messed up - you’re echoing the password as plain text first, then trying to echo it again as JSON. This creates malformed output that can’t be parsed. Fix your PHP to only output JSON once, and ditch the redundant JSON.parse calls.

you’re echoing twice in your php handler - first the password, then the json encoded version. plus, you’re setting the content type after already echoing output, which won’t work. remove the first echo and just return the json_encode part.

Your JavaScript is the problem. You’re setting contentType: "application/json" but sending regular form data. WordPress expects form-encoded data, not JSON. Just remove that contentType line and let jQuery handle it automatically.

Your PHP function’s also broken. You’re echoing the password twice and setting headers after output. Fix it like this: function handle_password_creation() { $new_password = wp_generate_password(8, true, false); wp_send_json_success($new_password); }. The wp_send_json_success() function handles headers and encoding for you.

That’ll fix your 400 error.