monzo / response

Monzo's real-time incident response and reporting tool ⚡️
MIT License
1.53k stars 165 forks source link

KeyError: 'ts' #26

Closed titogarrido closed 5 years ago

titogarrido commented 5 years ago

Hi,

I am trying to create an incident and I am receiving:

response    | [26/May/2019 19:52:02] "POST /slack/action HTTP/1.1" 200 0
response    |  ERROR - signals    - 'ts'
response    | Traceback (most recent call last):
response    |   File "/app/slack/signals.py", line 21, in update_headline_after_incident_save
response    |     incident=instance
response    |   File "/usr/local/lib/python3.7/site-packages/django/db/models/manager.py", line 82, in manager_method
response    |     return getattr(self.get_queryset(), name)(*args, **kwargs)
response    |   File "/usr/local/lib/python3.7/site-packages/django/db/models/query.py", line 399, in get
response    |     self.model._meta.object_name
response    | slack.models.headline_post.HeadlinePost.DoesNotExist: HeadlinePost matching query does not exist.
response    |
response    | During handling of the above exception, another exception occurred:
response    |
response    | Traceback (most recent call last):
response    |   File "/usr/local/lib/python3.7/site-packages/after_response/signals.py", line 19, in run
response    |     func(*args, **kwargs)
response    |   File "/app/slack/decorators/dialog_handler.py", line 30, in handle_dialog
response    |     callback(user_id, channel_id, submission, response_url, state)
response    |   File "/app/slack/dialog_handlers.py", line 31, in report_incident
response    |     severity=severity,
response    |   File "/app/core/models/incident.py", line 15, in create_incident
response    |     severity=severity,
response    |   File "/usr/local/lib/python3.7/site-packages/django/db/models/manager.py", line 82, in manager_method
response    |     return getattr(self.get_queryset(), name)(*args, **kwargs)
response    |   File "/usr/local/lib/python3.7/site-packages/django/db/models/query.py", line 413, in create
response    |     obj.save(force_insert=True, using=self.db)
response    |   File "/usr/local/lib/python3.7/site-packages/django/db/models/base.py", line 718, in save
response    |     force_update=force_update, update_fields=update_fields)
response    |   File "/usr/local/lib/python3.7/site-packages/django/db/models/base.py", line 758, in save_base
response    |     update_fields=update_fields, raw=raw, using=using,
response    |   File "/usr/local/lib/python3.7/site-packages/django/dispatch/dispatcher.py", line 175, in send
response    |     for receiver in self._live_receivers(sender)
response    |   File "/usr/local/lib/python3.7/site-packages/django/dispatch/dispatcher.py", line 175, in <listcomp>
response    |     for receiver in self._live_receivers(sender)
response    |   File "/app/slack/signals.py", line 27, in update_headline_after_incident_save
response    |     incident=instance
response    |   File "/app/slack/models/headline_post.py", line 16, in create_headline_post
response    |     incident=incident,
response    |   File "/usr/local/lib/python3.7/site-packages/django/db/models/manager.py", line 82, in manager_method
response    |     return getattr(self.get_queryset(), name)(*args, **kwargs)
response    |   File "/usr/local/lib/python3.7/site-packages/django/db/models/query.py", line 413, in create
response    |     obj.save(force_insert=True, using=self.db)
response    |   File "/usr/local/lib/python3.7/site-packages/django/db/models/base.py", line 718, in save
response    |     force_update=force_update, update_fields=update_fields)
response    |   File "/usr/local/lib/python3.7/site-packages/django/db/models/base.py", line 758, in save_base
response    |     update_fields=update_fields, raw=raw, using=using,
response    |   File "/usr/local/lib/python3.7/site-packages/django/dispatch/dispatcher.py", line 175, in send
response    |     for receiver in self._live_receivers(sender)
response    |   File "/usr/local/lib/python3.7/site-packages/django/dispatch/dispatcher.py", line 175, in <listcomp>
response    |     for receiver in self._live_receivers(sender)
response    |   File "/app/slack/signals.py", line 37, in update_headline_after_save
response    |     instance.update_in_slack()
response    |   File "/app/slack/models/headline_post.py", line 79, in update_in_slack
response    |     self.message_ts = response['ts']
response    | KeyError: 'ts'

Any clue?

danpalmer commented 5 years ago

I just got this as well. This might happen if the response from the Slack API is an error rather than a success (the ts identifies the message in a way, and no message was created). If you add a print(response), or print(response['error']) above that line then you should be able to see the error. In my case, the error was channel_not_found, as I had followed the setup instructions and used the #incidents channel, but not yet actually created the channel. I created the channel, and after restarting response it worked as expected.

pabsi commented 5 years ago

I followed the README's instructions to the letter and I am hitting this error too:

response    |   File "/app/slack/models/headline_post.py", line 79, in update_in_slack
response    |     self.message_ts = response['ts']
response    | KeyError: 'ts'

Channel exists, and it is public. I added the bot to it too by "@" it. As an extra, "@" ing the bot for help (@incident_bot help) does not do anything. Logs don't show anything either. All URLs udated to use ngrok ones.

As suggested by @danpalmer I added print(response) to slack/models/headline_post.py and got the following:

response    | {'ok': False, 'error': 'channel_not_found', 'headers': {'Content-Type': 'application/json; charset=utf-8', 'Content-Length': '60', 'Connection': 'keep-alive', 'Date': 'Fri, 14 Jun 2019 12:41:15 GMT', 'Server': 'Apache', 'X-Content-Type-Options': 'nosniff', 'X-Slack-Req-Id': 'xxxxxxxxxxxxxxx', 'X-OAuth-Scopes': 'identify,bot,commands,channels:history,channels:read,users:read,channels:write,chat:write:user,chat:write:bot', 'Expires': 'Mon, 26 Jul 1997 05:00:00 GMT', 'Cache-Control': 'private, no-cache, no-store, must-revalidate', 'Access-Control-Expose-Headers': 'x-slack-req-id', 'X-XSS-Protection': '0', 'X-Accepted-OAuth-Scopes': 'chat:write:bot', 'Vary': 'Accept-Encoding', 'Pragma': 'no-cache', 'Access-Control-Allow-Headers': 'slack-route, x-slack-version-ts', 'Strict-Transport-Security': 'max-age=31536000; includeSubDomains; preload', 'Referrer-Policy': 'no-referrer', 'Content-Encoding': 'gzip', 'Access-Control-Allow-Origin': '*', 'X-Via': 'haproxy-www-0q2r', 'X-Cache': 'Miss from cloudfront', 'Via': '1.1 63d897654686e9908c8e03c9efa9c27c.cloudfront.net (CloudFront)', 'X-Amz-Cf-Pop': 'LHR62-C2', 'X-Amz-Cf-Id': 'xxxxxxxxxxxxxxx=='}}

Key is 'error': 'channel_not_found'. Channel exists. I tried on two different channels even created a new one.

My setup:

INCIDENT_CHANNEL_NAME="001-incident-tests"
INCIDENT_BOT_NAME="incident_bot"
PAGERDUTY_ENABLED="False"

Any suggestions

EDIT: as per https://api.slack.com/methods/chat.postMessage :

channel_not_found : Value passed for channel was invalid

dsolsona commented 5 years ago

I'm currently having the same issue and in my case it seems to be due to having way too many channels in Slack.

In https://github.com/monzo/response/blob/master/response/settings/dev.py#L53-L56 the code tries to get the Slack channel ID by calling https://github.com/monzo/response/blob/master/response/settings/base.py#L191

My assumption is that this api call does not handle pagination properly, if you have more than 1000 channels in Slack the API call will return you a thousand and a cursor to get the next batch of channels. If get_channel_id doesn't find any channel then response will just set it to None and that pretty much breaks everything.

adamlphillips commented 5 years ago

This may also happen if you don't have enough permissions. You may need an additional scope. If you see the scope that is needed in slack oAuth permissions you may need to update your SLACK_TOKEN environment variable with the latest token.

time-less-ness commented 5 years ago

Any clues on this one?

I get the channel_not_found error, but:

INCIDENT_CHANNEL_NAME="incidents"

And I have an #incidents channel. We only have maybe a few hundred Slack channels (how would I know?). I'm going to try again now with a channel called 00-incidents and hopefully that will sort enough to the start (if the problem is too many channels).

UPDATE: Nope. I re-configured everything with INCIDENT_CHANNEL_NAME="00-incidents" and created the channel, and still get the same error.

time-less-ness commented 5 years ago

For precision, the error is:

response    | Error: channel_not_found, Need: None

Is this a whole different issue than the KeyError: 'ts' issue that this is attached to? I also get that, but I feel like maybe the ts KeyError problem is a generic thing you get all the time, and the most common cause right now is the channel_not_found? Just a guess from reading the Issue, but I might be just hoping since that's my particular situation.

milesbxf commented 5 years ago

The above responses are correct - this generally happens because the Slack API returns slightly weird responses - if there's an error, we get a response like this:

{
  "ok": false,
  "error": "channel_not_found"
}

Previously, the code would only look for the ["ts"] key, and not find it in this response, causing that error.

We've done some refactoring recently to the Slack client (in #83 ) so that it now explicitly checks any response from the Slack API for {"ok": true} and raises an exception if that's not present, which should make debugging issues like this much easier 🙏

time-less-ness commented 5 years ago

In my case, this was caused by Slack having too many channels. Ever since I added the cursor code, I never see this error/problem anymore.

milesbxf commented 5 years ago

We've released 0.1.1 which includes better error handling for Slack - it should be much easier to debug instances of this in future. If there are specific bugs around Slack handling (like the Slack channel cursoring @philovivero mentioned), please raise a new issue and we'll take it from there ❤️

https://github.com/monzo/response/releases/tag/release-0.1.1