TypeError: content must be a byte-string, not str

When I call anvil.http.request from the client, I receive the error TypeError: content must be a byte-string, not str.

The error does not occur when I call the same code from a server module.

This is not a huge problem because the method still works as designed (it sends a message to my slack account), and I can catch and swallow the error in an error_handler method, which stops it from showing up on the live webpage. However, I’d love to figure out how to get the error message to not show up in my App logs.

The following code exemplifies the issue:

Here is the error message:

Screenshot 2020-07-09 14.21.03

Note that the exception is not caught by the exception handler in the offending method. But it is caught by the error handler. I’m curious about why that would happen.

Thanks,
Matt

It may be happening because you’re doing the json encoding yourself with json.dumps(). There’s actually a json flag that might make your life a little simpler. See the docs for details.

Give this a go and see if it resolves your TypeError issue:

anvil.http.request(url=url,
                   method='POST',
                   data=data,
                   json=True)

As far as why it happens in client code but not server code, I’d wager they’re just different environments. I’m sure client code involves a lot more complexity since it needs to run as javascript in the browser. Server code doesn’t have that problem.

Let me know if this gets the job done for you. Happy to help more if I missed the mark, but next time please post your code as text so it’s copy/pasteable.

Is it possible that your client code is running as Python v2, instead of v3?

See Switching apps to client-side Python 3

Thanks for the suggestion, @p.colbert. Unfortunately, I’m already on v3.

Thanks very much, @kevin. I tried your suggested code but now I get an HttpError:0 exception. Anvil docs recommend that the best way to deal with this exception is to move the HTTP request to the server. This won’t work for me, though, because I am attempting to receive an alert every time the client stops loading live data (via a timer) due to a Connection to server failed exception generated by the client.

Good suggestion to post my code in a format that can be copied & pasted. Here is the updated code.

from ._anvil_designer import Form1Template
from anvil import *
import anvil.server
from datetime import datetime
import json

def error_handler(err):
  if isinstance(err, TypeError):
    print(f"Caught TypeError in handler")
  else:
    print(type(err))

set_default_error_handling(error_handler)

class Form1(Form1Template):

  def __init__(self, **properties):
    # Set Form properties and Data Bindings.
    self.init_components(**properties)

  def button_1_click(self, **event_args):
    try:
      url = "https://slack.com/api/api.test"
      dt_str = datetime.now().isoformat() 
      data = {
        'text': "Test POST",
      }  
      anvil.http.request(url=url, method="POST", data=data, json=True)
    except TypeError:
      print("Caught TypeError in button method")

A new exception definitely counts as progress! Sounds like a CORS issue. Since it’s a third-party API, there’s not a whole lot you can do to overcome that without Slack’s help.

Is there a reason you can’t create a server function as a wrapper and then call that from the form? Something like this…

# in the form (client code)
def button_1_click(self, **event_args):
    url = "https://slack.com/api/api.test"
    data = {'text': f"Test POST",}  
    take_action = anvil.server.call('slack_api_caller', url, data)
    if take_action:
        do_the_thing_now()
# ... and then in a server module.
@anvil.server.callable
def slack_api_caller(url, data, json=True):
    response = anvil.http.request(url=url, data=data, json=json)
    if response is some_condition:
        return True
    else:
        return False

Heads up - I’m going to send you a quick dm as well, so look out for that.

Hi @kevin,

I was attempting to not rely on a server call because I’m trying to get alerted (via slack, or really, any other method) when my app is generating an exception on the client-side. The error message popping up on the client is “Connection to server failed”. It is difficult for me to predict when this exception will occur but it happens about once a day and is generated from one or both of the timer-based methods I have running on the client. One timer has a 60 second interval and the other has a 30 second interval. Both timer methods make server-based calls.

When the exception occurs, the client stops showing up-to-date data to my customer. Usually, the only way to fix the problem is to refresh the browser. My preference, of course, is to get rid of the exception. But until I figure out how to fix it, being alerted will allow me to refresh my customer’s browser via remote-control.

My reasoning is that if the exception truly means that the client has lost the ability to connect to the server, then attempting to be alerted about the error by calling a server method won’t work. However, I have to admit that I have not confirmed that hypothesis. Based on what you point out in your response, I think trying to call a server method is my next best step.

Thanks again for the help moving forward on this issue, and especially for your code examples.