Repository: getmoto/moto

Issue:
Bug: DynamoDB table doesnt exist, then hangs
[This](https://github.com/spulec/moto/blob/master/moto/dynamodb2/responses.py#L298) `table` variable ends up being `None`. 

We should have a check [here](https://github.com/spulec/moto/blob/master/moto/dynamodb2/responses.py#L284) which returns a table not found if its None.

I'll PR it eventually if no one else beats me to it, but am deep down the rabbit hole with other stuff atm.

Stacktrace
```
Traceback (most recent call last):
  File "/usr/lib/python3.6/site-packages/werkzeug/serving.py", line 209, in run_wsgi
    execute(self.server.app)
  File "/usr/lib/python3.6/site-packages/werkzeug/serving.py", line 197, in execute
    application_iter = app(environ, start_response)
  File "/usr/lib/python3.6/site-packages/moto/server.py", line 92, in __call__
    return backend_app(environ, start_response)
  File "/usr/lib/python3.6/site-packages/flask/app.py", line 1997, in __call__
    return self.wsgi_app(environ, start_response)
  File "/usr/lib/python3.6/site-packages/flask/app.py", line 1985, in wsgi_app
    response = self.handle_exception(e)
  File "/usr/lib/python3.6/site-packages/flask/app.py", line 1540, in handle_exception
    reraise(exc_type, exc_value, tb)
  File "/usr/lib/python3.6/site-packages/flask/_compat.py", line 33, in reraise
    raise value
  File "/usr/lib/python3.6/site-packages/flask/app.py", line 1982, in wsgi_app
    response = self.full_dispatch_request()
  File "/usr/lib/python3.6/site-packages/flask/app.py", line 1614, in full_dispatch_request
    rv = self.handle_user_exception(e)
  File "/usr/lib/python3.6/site-packages/flask/app.py", line 1517, in handle_user_exception
    reraise(exc_type, exc_value, tb)
  File "/usr/lib/python3.6/site-packages/flask/_compat.py", line 33, in reraise
    raise value
  File "/usr/lib/python3.6/site-packages/flask/app.py", line 1612, in full_dispatch_request
    rv = self.dispatch_request()
  File "/usr/lib/python3.6/site-packages/flask/app.py", line 1598, in dispatch_request
    return self.view_functions[rule.endpoint](**req.view_args)
  File "/usr/lib/python3.6/site-packages/moto/core/utils.py", line 131, in __call__
    result = self.callback(request, request.url, {})
  File "/usr/lib/python3.6/site-packages/moto/core/responses.py", line 111, in dispatch
    return cls()._dispatch(*args, **kwargs)
  File "/usr/lib/python3.6/site-packages/moto/core/responses.py", line 179, in _dispatch
    return self.call_action()
  File "/usr/lib/python3.6/site-packages/moto/dynamodb2/responses.py", line 32, in call_action
    response = getattr(self, endpoint)()
  File "/usr/lib/python3.6/site-packages/moto/dynamodb2/responses.py", line 298, in query
    index = table.schema
AttributeError: 'NoneType' object has no attribute 'schema'
```
Bug: DynamoDB table doesnt exist, then hangs
[This](https://github.com/spulec/moto/blob/master/moto/dynamodb2/responses.py#L298) `table` variable ends up being `None`. 

We should have a check [here](https://github.com/spulec/moto/blob/master/moto/dynamodb2/responses.py#L284) which returns a table not found if its None.

I'll PR it eventually if no one else beats me to it, but am deep down the rabbit hole with other stuff atm.

Stacktrace
```
Traceback (most recent call last):
  File "/usr/lib/python3.6/site-packages/werkzeug/serving.py", line 209, in run_wsgi
    execute(self.server.app)
  File "/usr/lib/python3.6/site-packages/werkzeug/serving.py", line 197, in execute
    application_iter = app(environ, start_response)
  File "/usr/lib/python3.6/site-packages/moto/server.py", line 92, in __call__
    return backend_app(environ, start_response)
  File "/usr/lib/python3.6/site-packages/flask/app.py", line 1997, in __call__
    return self.wsgi_app(environ, start_response)
  File "/usr/lib/python3.6/site-packages/flask/app.py", line 1985, in wsgi_app
    response = self.handle_exception(e)
  File "/usr/lib/python3.6/site-packages/flask/app.py", line 1540, in handle_exception
    reraise(exc_type, exc_value, tb)
  File "/usr/lib/python3.6/site-packages/flask/_compat.py", line 33, in reraise
    raise value
  File "/usr/lib/python3.6/site-packages/flask/app.py", line 1982, in wsgi_app
    response = self.full_dispatch_request()
  File "/usr/lib/python3.6/site-packages/flask/app.py", line 1614, in full_dispatch_request
    rv = self.handle_user_exception(e)
  File "/usr/lib/python3.6/site-packages/flask/app.py", line 1517, in handle_user_exception
    reraise(exc_type, exc_value, tb)
  File "/usr/lib/python3.6/site-packages/flask/_compat.py", line 33, in reraise
    raise value
  File "/usr/lib/python3.6/site-packages/flask/app.py", line 1612, in full_dispatch_request
    rv = self.dispatch_request()
  File "/usr/lib/python3.6/site-packages/flask/app.py", line 1598, in dispatch_request
    return self.view_functions[rule.endpoint](**req.view_args)
  File "/usr/lib/python3.6/site-packages/moto/core/utils.py", line 131, in __call__
    result = self.callback(request, request.url, {})
  File "/usr/lib/python3.6/site-packages/moto/core/responses.py", line 111, in dispatch
    return cls()._dispatch(*args, **kwargs)
  File "/usr/lib/python3.6/site-packages/moto/core/responses.py", line 179, in _dispatch
    return self.call_action()
  File "/usr/lib/python3.6/site-packages/moto/dynamodb2/responses.py", line 32, in call_action
    response = getattr(self, endpoint)()
  File "/usr/lib/python3.6/site-packages/moto/dynamodb2/responses.py", line 298, in query
    index = table.schema
AttributeError: 'NoneType' object has no attribute 'schema'
```


Discussion:

Resolving patch:
diff --git a/moto/dynamodb2/responses.py b/moto/dynamodb2/responses.py
--- a/moto/dynamodb2/responses.py
+++ b/moto/dynamodb2/responses.py
@@ -21,8 +21,8 @@ def get_endpoint_name(self, headers):
         if match:
             return match.split(".")[1]
 
-    def error(self, type_, status=400):
-        return status, self.response_headers, dynamo_json_dump({'__type': type_})
+    def error(self, type_, message, status=400):
+        return status, self.response_headers, dynamo_json_dump({'__type': type_, 'message': message})
 
     def call_action(self):
         self.body = json.loads(self.body or '{}')
@@ -82,7 +82,7 @@ def create_table(self):
             return dynamo_json_dump(table.describe())
         else:
             er = 'com.amazonaws.dynamodb.v20111205#ResourceInUseException'
-            return self.error(er)
+            return self.error(er, 'Resource in use')
 
     def delete_table(self):
         name = self.body['TableName']
@@ -91,7 +91,7 @@ def delete_table(self):
             return dynamo_json_dump(table.describe())
         else:
             er = 'com.amazonaws.dynamodb.v20111205#ResourceNotFoundException'
-            return self.error(er)
+            return self.error(er, 'Requested resource not found')
 
     def tag_resource(self):
         tags = self.body['Tags']
@@ -120,7 +120,7 @@ def list_tags_of_resource(self):
             return json.dumps({'Tags': tags_resp})
         except AttributeError:
             er = 'com.amazonaws.dynamodb.v20111205#ResourceNotFoundException'
-            return self.error(er)
+            return self.error(er, 'Requested resource not found')
 
     def update_table(self):
         name = self.body['TableName']
@@ -138,7 +138,7 @@ def describe_table(self):
             table = dynamodb_backend2.tables[name]
         except KeyError:
             er = 'com.amazonaws.dynamodb.v20111205#ResourceNotFoundException'
-            return self.error(er)
+            return self.error(er, 'Requested resource not found')
         return dynamo_json_dump(table.describe(base_key='Table'))
 
     def put_item(self):
@@ -190,7 +190,7 @@ def put_item(self):
                 name, item, expected, overwrite)
         except ValueError:
             er = 'com.amazonaws.dynamodb.v20111205#ConditionalCheckFailedException'
-            return self.error(er)
+            return self.error(er, 'A condition specified in the operation could not be evaluated.')
 
         if result:
             item_dict = result.to_json()
@@ -198,7 +198,7 @@ def put_item(self):
             return dynamo_json_dump(item_dict)
         else:
             er = 'com.amazonaws.dynamodb.v20111205#ResourceNotFoundException'
-            return self.error(er)
+            return self.error(er, 'Requested resource not found')
 
     def batch_write_item(self):
         table_batches = self.body['RequestItems']
@@ -235,15 +235,14 @@ def get_item(self):
             item = dynamodb_backend2.get_item(name, key)
         except ValueError:
             er = 'com.amazon.coral.validate#ValidationException'
-            return self.error(er, status=400)
+            return self.error(er, 'Validation Exception')
         if item:
             item_dict = item.describe_attrs(attributes=None)
             item_dict['ConsumedCapacityUnits'] = 0.5
             return dynamo_json_dump(item_dict)
         else:
             # Item not found
-            er = '{}'
-            return self.error(er, status=200)
+            return 200, self.response_headers, '{}'
 
     def batch_get_item(self):
         table_batches = self.body['RequestItems']
@@ -282,6 +281,12 @@ def query(self):
             value_alias_map = self.body['ExpressionAttributeValues']
 
             table = dynamodb_backend2.get_table(name)
+
+            # If table does not exist
+            if table is None:
+                return self.error('com.amazonaws.dynamodb.v20120810#ResourceNotFoundException',
+                                  'Requested resource not found')
+
             index_name = self.body.get('IndexName')
             if index_name:
                 all_indexes = (table.global_indexes or []) + \
@@ -350,7 +355,7 @@ def query(self):
                         filter_kwargs[key] = value
                 if hash_key_name is None:
                     er = "'com.amazonaws.dynamodb.v20120810#ResourceNotFoundException"
-                    return self.error(er)
+                    return self.error(er, 'Requested resource not found')
                 hash_key = key_conditions[hash_key_name][
                     'AttributeValueList'][0]
                 if len(key_conditions) == 1:
@@ -359,7 +364,7 @@ def query(self):
                 else:
                     if range_key_name is None and not filter_kwargs:
                         er = "com.amazon.coral.validate#ValidationException"
-                        return self.error(er)
+                        return self.error(er, 'Validation Exception')
                     else:
                         range_condition = key_conditions.get(range_key_name)
                         if range_condition:
@@ -381,7 +386,7 @@ def query(self):
             exclusive_start_key, scan_index_forward, index_name=index_name, **filter_kwargs)
         if items is None:
             er = 'com.amazonaws.dynamodb.v20111205#ResourceNotFoundException'
-            return self.error(er)
+            return self.error(er, 'Requested resource not found')
 
         result = {
             "Count": len(items),
@@ -417,7 +422,7 @@ def scan(self):
 
         if items is None:
             er = 'com.amazonaws.dynamodb.v20111205#ResourceNotFoundException'
-            return self.error(er)
+            return self.error(er, 'Requested resource not found')
 
         result = {
             "Count": len(items),
@@ -436,7 +441,7 @@ def delete_item(self):
         table = dynamodb_backend2.get_table(name)
         if not table:
             er = 'com.amazonaws.dynamodb.v20120810#ConditionalCheckFailedException'
-            return self.error(er)
+            return self.error(er, 'A condition specified in the operation could not be evaluated.')
 
         item = dynamodb_backend2.delete_item(name, keys)
         if item and return_values == 'ALL_OLD':
@@ -496,10 +501,10 @@ def update_item(self):
                 expected)
         except ValueError:
             er = 'com.amazonaws.dynamodb.v20111205#ConditionalCheckFailedException'
-            return self.error(er)
+            return self.error(er, 'A condition specified in the operation could not be evaluated.')
         except TypeError:
             er = 'com.amazonaws.dynamodb.v20111205#ValidationException'
-            return self.error(er)
+            return self.error(er, 'Validation Exception')
 
         item_dict = item.to_json()
         item_dict['ConsumedCapacityUnits'] = 0.5


Test patch:
diff --git a/tests/test_dynamodb2/test_dynamodb.py b/tests/test_dynamodb2/test_dynamodb.py
--- a/tests/test_dynamodb2/test_dynamodb.py
+++ b/tests/test_dynamodb2/test_dynamodb.py
@@ -181,3 +181,16 @@ def test_item_add_empty_string_exception():
     ex.exception.response['Error']['Message'].should.equal(
         'One or more parameter values were invalid: An AttributeValue may not contain an empty string'
     )
+
+
+@requires_boto_gte("2.9")
+@mock_dynamodb2
+def test_query_invalid_table():
+    conn = boto3.client('dynamodb',
+                        region_name='us-west-2',
+                        aws_access_key_id="ak",
+                        aws_secret_access_key="sk")
+    try:
+        conn.query(TableName='invalid_table', KeyConditionExpression='index1 = :partitionkeyval', ExpressionAttributeValues={':partitionkeyval': {'S':'test'}})
+    except ClientError as exception:
+        assert exception.response['Error']['Code'] == "ResourceNotFoundException"
\ No newline at end of file