'"The browser (or proxy) sent a request that this server could not understand."

I am trying to build a website with an ML model using Flask and Python.

I keep getting this error when I input the values to get the prediction

The browser (or proxy) sent a request that this server could not understand.

Here is the code I have written so far.

This is the app.py file

from flask import Flask, request, render_template
import pickle

app = Flask(__name__)
model = pickle.load(open('model.pkl', 'rb'))  # loading the model

@app.route('/')
def home():
    return render_template('index.html')

@app.route('/predict',methods=['POST'])
def predict():
    """Grabs the input values and uses them to make prediction"""
    # rooms = int(request.form["rooms"])
    # distance = int(request.form["distance"])

    radius_mean  =  int(request.form["radius_mean"])
    texture_mean=   int(request.form["texture_mean"])
    perimeter_mean= int(request.form["perimeter_mean"])
    area_mean=  int(request.form["area_mean"])
    smoothness_mean=    int(request.form["smoothness_mean"])
    compactness_mean=   int(request.form["compactness_mean"])
    concavity_mean= int(request.form["concavity_mean"])
    concave_points_mean =   int(request.form["concave_points_mean"])
    symmetry_mean=  int(request.form["symmetry_mean"])
    fractal_dimension_mean= int(request.form["fractal_dimension_mean"])
    radius_se=  int(request.form[radius_se])
    texture_se= int(request.form["texture_se"])
    perimeter_se=   int(request.form["perimeter_se"])
    area_se=    int(request.form["area_se"])
    smoothness_se=  int(request.form["smoothness_se"])
    compactness_se= int(request.form["compactness_se"])
    concavity_se=   int(request.form["concavity_se"])
    concave_points_se=  int(request.form["concave_points_se"])
    symmetry_se=    int(request.form["symmetry_se"])
    fractal_dimension_se=   int(request.form["fractal_dimension_se"])
    radius_worst=   int(request.form["radius_worst"])
    texture_worst=  int(request.form["texture_worst"])
    perimeter_worst=    int(request.form["perimeter_worst"])
    area_worst= int(request.form["area_worst"])
    smoothness_worst=   int(request.form["smoothness_worst"])
    compactness_worst=  int(request.form["compactness_worst"])
    concavity_worst=    int(request.form["concavity_worst"])
    concave_points_worst=   int(request.form["concave_points_worst"])
    symmetry_worst= int(request.form["symmetry_worst"])
    fractal_dimension_worst=    int(request.form["fractal_dimension_worst"])


    prediction = model.predict
    ([[radius_mean, 
    texture_mean, 
    perimeter_mean, 
    area_mean, 
    smoothness_mean, 
    compactness_mean, 
    concavity_mean, 
    concave_points_mean, 
    symmetry_mean, 
    fractal_dimension_mean, 
    radius_se, 
    texture_se, 
    perimeter_se, 
    area_se, 
    smoothness_se, 
    compactness_se, 
    concavity_se, 
    concave_points_se, 
    symmetry_se, 
    fractal_dimension_se, 
    radius_worst, 
    texture_worst, 
    perimeter_worst, 
    area_worst, 
    smoothness_worst, 
    compactness_worst, 
    concavity_worst, 
    concave_points_worst, 
    symmetry_worst,
    fractal_dimension_worst
    ]])  # this returns a list e.g. [127.20488798], so pick first element [0]
    output = round(prediction[0], 30) 

    return render_template('index.html', prediction_text=f'A tumour with {rooms} {radius_mean}{texture_mean} {perimeter_mean} {area_mean} {smoothness_mean} {compactness_mean} {concavity_mean} {concave_points_mean} {symmetry_mean} {fractal_dimension_mean} {radius_se} {texture_se} {perimeter_se} {area_se} {smoothness_se} {compactness_se} {concavity_se} {concave_points_se} {symmetry_se} {fractal_dimension_se} {radius_worst} {texture_worst} {perimeter_worst} {area_worst} {smoothness_worst} {compactness_worst} {concavity_worst} {concave_points_worst} {symmetry_worst} {fractal_dimension_worst} from the city center has a value of {output}')


if __name__ == "__main__":
    app.run()

This is the index.html file:

<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>

    <link href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-1BmE4kWBq78iYhFldvKuhfTAU6auU8tT94WrHftjDbrCEXSU1oBoqyl2QvZ6jIW3" crossorigin="anonymous">

     <!-- Nav Bar -->
  <nav class="navbar navbar-expand-lg navbar-light bg-light">
    <div class="container-fluid">
      <a class="navbar-brand" href="#">Navbar</a>
      <button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarSupportedContent" aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation">
        <span class="navbar-toggler-icon"></span>
      </button>
      <div class="collapse navbar-collapse" id="navbarSupportedContent">
        <ul class="navbar-nav me-auto mb-2 mb-lg-0">
          <li class="nav-item">
            <a class="nav-link active" aria-current="page" href="#">Home</a>
          </li>
          <li class="nav-item">
            <a class="nav-link" href="#">Link</a>
          </li>
          <li class="nav-item dropdown">
            <a class="nav-link dropdown-toggle" href="#" id="navbarDropdown" role="button" data-bs-toggle="dropdown" aria-expanded="false">
              Dropdown
            </a>
            <ul class="dropdown-menu" aria-labelledby="navbarDropdown">
              <li><a class="dropdown-item" href="#">Action</a></li>
              <li><a class="dropdown-item" href="#">Another action</a></li>
              <li><hr class="dropdown-divider"></li>
              <li><a class="dropdown-item" href="#">Something else here</a></li>
            </ul>
          </li>
          <li class="nav-item">
            <a class="nav-link disabled">Disabled</a>
          </li>
        </ul>
        <form class="d-flex">
          <input class="form-control me-2" type="search" placeholder="Search" aria-label="Search">
          <button class="btn btn-outline-success" type="submit">Search</button>
        </form>
      </div>
    </div>
  </nav>
  
</head>
<body>
    <div class="login">
        <h2>Price Prediction</h2>
          <p>Introduce the number of rooms and distance:</p>
           <!-- Inputs for our ML model -->
            <form action="{{ url_for('predict')}}"method="post">
              <input type="text" name="radius_mean  " placeholder="radius_mean " required="required" />
              <input type="text" name="texture_mean" placeholder="texture_mean" required="required"/>
              <input type="text" name="perimeter_mean" placeholder="perimeter_mean" required="required" />
              <input type="text" name="area_mean" placeholder="area_mean" required="required"/>
              <input type="text" name="smoothness_mean" placeholder="smoothness_mean" required="required" />
              <input type="text" name="compactness_mean" placeholder="compactness_mean" required="required"/>
              <input type="text" name="concavity_mean" placeholder="concavity_mean" required="required" />
              <input type="text" name="concave_points_mean" placeholder="concave_points_mean" required="required"/>
              <input type="text" name="symmetry_mean" placeholder="symmetry_mean" required="required" />
              <input type="text" name="fractal_dimension_mean" placeholder="fractal_dimension_mean"required="required"/>

              <input type="text" name="radius_se " placeholder="radius_se " required="required" />
              <input type="text" name="texture_se" placeholder="texture_se" required="required"/>
              <input type="text" name="perimeter_se" placeholder="perimeter_se"required="required" />
              <input type="text" name="area_se" placeholder="area_se" required="required"/>
              <input type="text" name="smoothness_se" placeholder="smoothness_se" required="required" />
              <input type="text" name="compactness_se" placeholder="compactness_se"  required="required"/>
              <input type="text" name="concavity_se" placeholder="concavity_se"  required="required" />
              <input type="text" name="concave_points_se" placeholder="concave_points_se"required="required"/>
              <input type="text" name="symmetry_se" placeholder="symmetry_se" required="required" />
              <input type="text" name="fractal_dimension_se" placeholder="fractal_dimension_se"required="required"/>

              <input type="text" name="radius_worst" placeholder="radius_worst"required="required" />
              <input type="text" name="texture_worst" placeholder="texture_worst" required="required"/>
              <input type="text" name="perimeter_worst" placeholder="perimeter_worst" required="required" />
              <input type="text" name="area_worst" placeholder="area_worst" required="required"/>
              <input type="text" name="smoothness_worst" placeholder="smoothness_worst"  required="required" />
              <input type="text" name="compactness_worst" placeholder="compactness_worst" required="required"/>
              <input type="text" name="concavity_worst" placeholder="concavity_worst" required="required" />
              <input type="text" name="concave_points_worst" placeholder="concave_points_worst" required="required"/>
              <input type="text" name="symmetry_worst" placeholder="symmetry_worst"  required="required" />
              <input type="text" name="fractal_dimension_worst" placeholder="fractal_dimension_worst" required="required"/>

              <button type="submit" class="btn btn-primary btn-block btn-large">Predict Value!</button>
            </form>
         
          <br>
          <br>
       </div>
</body>
</html>

The image attached shows the dataset and the columns present. enter image description here

Any ideas on how to fix this error?



Solution 1:[1]

Flask actually indicates the cause of the error.

  • On the browser after clicking on the Predict button screenshot of the error on the browser - top half ... screenshot of the error on the browser - bottom half
  • On the server-side logs:
    werkzeug.exceptions.BadRequestKeyError: 400 Bad Request: The browser (or proxy) sent a request that this server could not understand.
    KeyError: 'radius_mean'
    

The initial problem is that your keys have some extra spaces:

  • index.html
    <input type="text" name="radius_mean  " .../>
                                        ^
                                        | There are 2 trailing spaces!
    
  • view function
    radius_mean  =  int(request.form["radius_mean"])
    

The spaces are not automatically stripped, and spaces matter:

In [8]: "radius_mean" == "radius_mean  "
Out[8]: False

Check all your keys on your HTML and Python code, and make sure they are consistent. The same error will also happen if your view function tries to access a form key that is not in the HTML template.

To help you debug, on your view function, you can check what request.form contains, which is just like a dictionary. You can use your debugger or do print(request.form.keys()).

A big improvement you can do here is to define an iterable (ex. list, tuple, etc.) to store all the keys. Pass that iterable to your HTML template, and dynamically generate the form <input> for each key, since your example shows they are all just copy-pasted with different name's and placeholder's. Then in your view function, again loop through this same iterable to parse the form.

app = Flask(__name__)

FORM_KEYS = (
    "radius_mean",
    "texture_mean",
    "perimeter_mean",
    "area_mean",
    "smoothness_mean",
    # Add the other keys here
)

@app.route("/")
def home():
    return render_template("index.html", form_keys=FORM_KEYS)

@app.route("/predict", methods=["POST"])
def predict():
    # This is a dictionary comprehension.
    # You can also manually assign the values one-by-one
    form_values = {
        form_key: int(request.form[form_key])
        for form_key in FORM_KEYS
    }  

    model_values = list(form_values.values())
    prediction = model.predict([model_values])
    ...
<form action="{{ url_for('predict')}}" method="post">
    {% for form_key in form_keys %}
      <input type="text" name="{{ form_key }}" placeholder="{{ form_key }}" required="required" /> 
    {% endfor %}

    <button type="submit" class="btn btn-primary btn-block btn-large">Predict Value!</button>
</form>

That should help prevent inconsistencies in the form keys, and improves the maintainability since you only need to update and check the keys in 1 place.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1