I spent hours trying to solve this bug and the solution was so simple. 
My rpcpassword in my bitcoin.conf file contained a '#' character.

Prevent this from happening, by outputting this an error or warning when users run bitcoind.

Right now, you can have a # character as a password and it will work on the command line but will fail when you JSON-RPC.
{
    {
        LOCK(cs_args);
        m_config_args.clear();
    }
    const std::string confPath = GetArg("-conf", BITCOIN_CONF_FILENAME);
    fsbridge::ifstream stream(GetConfigFile(confPath));
    
    if (stream.good()) {
        if (!ReadConfigStream(stream, error, ignore_invalid_keys)) {
            return false;
        }
        
        
        bool emptyIncludeConf;
        {
            LOCK(cs_args);
            emptyIncludeConf = m_override_args.count("-includeconf") == 0;
        }
        if (emptyIncludeConf) {
            std::string chain_id = GetChainName();
            std::vector<std::string> includeconf(GetArgs("-includeconf"));
            {
                
                
                std::vector<std::string> includeconf_net(GetArgs(std::string("-") + chain_id + ".includeconf"));
                includeconf.insert(includeconf.end(), includeconf_net.begin(), includeconf_net.end());