diff --git a/src/php/ext/grpc/call.c b/src/php/ext/grpc/call.c
index 7ae4c1b06be42bffbb1f67ba401b1a66cf56e158..7f4f221caa08a7aaeec786e340fff2cf078b0ad7 100755
--- a/src/php/ext/grpc/call.c
+++ b/src/php/ext/grpc/call.c
@@ -126,6 +126,7 @@ int php_grpc_call_add_metadata_array_walk(void *elem TSRMLS_DC,
                                           int num_args,
                                           va_list args,
                                           zend_hash_key *hash_key){
+  grpc_call_error error_code;
   zval **data = (zval**)elem;
   grpc_metadata metadata;
   grpc_call *call = va_arg(args, grpc_call*);
@@ -146,7 +147,8 @@ int php_grpc_call_add_metadata_array_walk(void *elem TSRMLS_DC,
       metadata.key = (char*)key;
       metadata.value = Z_STRVAL_P(*data);
       metadata.value_length = Z_STRLEN_P(*data);
-      grpc_call_add_metadata(call, &metadata, 0u);
+      error_code = grpc_call_add_metadata(call, &metadata, 0u);
+      MAYBE_THROW_CALL_ERROR(add_metadata, error_code);
       break;
     case IS_ARRAY:
       inner_hash = Z_ARRVAL_P(*data);
@@ -248,9 +250,10 @@ PHP_METHOD(Call, add_metadata){
  * @param long $finished_tag The tag to associate with the finished event
  * @param long $flags A bitwise combination of the Grpc\WRITE_* constants
  * (optional)
- * @return long Error code
+ * @return Void
  */
 PHP_METHOD(Call, start_invoke){
+  grpc_call_error error_code;
   long tag1;
   long tag2;
   long tag3;
@@ -276,12 +279,13 @@ PHP_METHOD(Call, start_invoke){
   wrapped_grpc_completion_queue *queue =
     (wrapped_grpc_completion_queue*)zend_object_store_get_object(
         queue_obj TSRMLS_CC);
-  RETURN_LONG(grpc_call_start_invoke(call->wrapped,
-                                     queue->wrapped,
-                                     (void*)tag1,
-                                     (void*)tag2,
-                                     (void*)tag3,
-                                     (gpr_uint32)flags));
+  error_code = grpc_call_start_invoke(call->wrapped,
+                                      queue->wrapped,
+                                      (void*)tag1,
+                                      (void*)tag2,
+                                      (void*)tag3,
+                                      (gpr_uint32)flags);
+  MAYBE_THROW_CALL_ERROR(start_invoke, error_code);
 }
 
 /**
@@ -292,11 +296,12 @@ PHP_METHOD(Call, start_invoke){
  * @param long $finished_tag The tag to associate with the finished event
  * @param long $flags A bitwise combination of the Grpc\WRITE_* constants
  * (optional)
- * @return long Error code
+ * @return Void
  */
 PHP_METHOD(Call, server_accept){
   long tag;
   zval *queue_obj;
+  grpc_call_error error_code;
   /* "Ol|l" == 1 Object, 1 long */
   if(zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC,
                            "Ol",
@@ -314,12 +319,14 @@ PHP_METHOD(Call, server_accept){
   wrapped_grpc_completion_queue *queue =
     (wrapped_grpc_completion_queue*)zend_object_store_get_object(
         queue_obj TSRMLS_CC);
-  RETURN_LONG(grpc_call_server_accept(call->wrapped,
-                                      queue->wrapped,
-                                      (void*)tag));
+  error_code = grpc_call_server_accept(call->wrapped,
+                                       queue->wrapped,
+                                       (void*)tag);
+  MAYBE_THROW_CALL_ERROR(server_accept, error_code);
 }
 
 PHP_METHOD(Call, server_end_initial_metadata) {
+  grpc_call_error error_code;
   long flags = 0;
   /* "|l" == 1 optional long */
   if(zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC,
@@ -332,17 +339,19 @@ PHP_METHOD(Call, server_end_initial_metadata) {
   }
   wrapped_grpc_call *call = (wrapped_grpc_call*)zend_object_store_get_object(
       getThis() TSRMLS_CC);
-  RETURN_LONG(grpc_call_server_end_initial_metadata(call->wrapped, flags));
+  error_code = grpc_call_server_end_initial_metadata(call->wrapped, flags);
+  MAYBE_THROW_CALL_ERROR(server_end_initial_metadata, error_code);
 }
 
 /**
  * Called by clients to cancel an RPC on the server.
- * @return long Error code
+ * @return Void
  */
 PHP_METHOD(Call, cancel){
   wrapped_grpc_call *call = (wrapped_grpc_call*)zend_object_store_get_object(
       getThis() TSRMLS_CC);
-  RETURN_LONG(grpc_call_cancel(call->wrapped));
+  grpc_call_error error_code = grpc_call_cancel(call->wrapped);
+  MAYBE_THROW_CALL_ERROR(cancel, error_code);
 }
 
 /**
@@ -351,9 +360,10 @@ PHP_METHOD(Call, cancel){
  * @param long $tag The tag to associate with this write
  * @param long $flags A bitwise combination of the Grpc\WRITE_* constants
  * (optional)
- * @return long Error code
+ * @return Void
  */
 PHP_METHOD(Call, start_write){
+  grpc_call_error error_code;
   wrapped_grpc_call *call = (wrapped_grpc_call*)zend_object_store_get_object(
       getThis() TSRMLS_CC);
   char *buffer;
@@ -372,10 +382,11 @@ PHP_METHOD(Call, start_write){
         1 TSRMLS_CC);
     return;
   }
-  RETURN_LONG(grpc_call_start_write(call->wrapped,
-                                    string_to_byte_buffer(buffer, buffer_len),
-                                    (void*)tag,
-                                    (gpr_uint32)flags));
+  error_code = grpc_call_start_write(call->wrapped,
+                                     string_to_byte_buffer(buffer, buffer_len),
+                                     (void*)tag,
+                                     (gpr_uint32)flags);
+  MAYBE_THROW_CALL_ERROR(start_write, error_code);
 }
 
 /**
@@ -383,9 +394,10 @@ PHP_METHOD(Call, start_write){
  * @param long $status_code The status code to send
  * @param string $status_details The status details to send
  * @param long $tag The tag to associate with this status
- * @return long Error code
+ * @return Void
  */
 PHP_METHOD(Call, start_write_status){
+  grpc_call_error error_code;
   wrapped_grpc_call *call = (wrapped_grpc_call*)zend_object_store_get_object(
       getThis() TSRMLS_CC);
   long status_code;
@@ -404,17 +416,19 @@ PHP_METHOD(Call, start_write_status){
         1 TSRMLS_CC);
     return;
   }
-  RETURN_LONG(grpc_call_start_write_status(call->wrapped,
-                                           (grpc_status_code)status_code,
-                                           status_details,
-                                           (void*)tag));
+  error_code = grpc_call_start_write_status(call->wrapped,
+                                            (grpc_status_code)status_code,
+                                            status_details,
+                                            (void*)tag);
+  MAYBE_THROW_CALL_ERROR(start_write_status, error_code);
 }
 
 /**
  * Indicate that there are no more messages to send
- * @return long Error code
+ * @return Void
  */
 PHP_METHOD(Call, writes_done){
+  grpc_call_error error_code;
   wrapped_grpc_call *call = (wrapped_grpc_call*)zend_object_store_get_object(
       getThis() TSRMLS_CC);
   long tag;
@@ -425,16 +439,18 @@ PHP_METHOD(Call, writes_done){
                          1 TSRMLS_CC);
     return;
   }
-  RETURN_LONG(grpc_call_writes_done(call->wrapped, (void*)tag));
+  error_code = grpc_call_writes_done(call->wrapped, (void*)tag);
+  MAYBE_THROW_CALL_ERROR(writes_done, error_code);
 }
 
 /**
  * Initiate a read on a call. Output event contains a byte buffer with the
  * result of the read
  * @param long $tag The tag to associate with this read
- * @return long Error code
+ * @return Void
  */
 PHP_METHOD(Call, start_read){
+  grpc_call_error error_code;
   wrapped_grpc_call *call = (wrapped_grpc_call*)zend_object_store_get_object(
       getThis() TSRMLS_CC);
   long tag;
@@ -445,7 +461,8 @@ PHP_METHOD(Call, start_read){
                          1 TSRMLS_CC);
     return;
   }
-  RETURN_LONG(grpc_call_start_read(call->wrapped, (void*)tag));
+  error_code = grpc_call_start_read(call->wrapped, (void*)tag);
+  MAYBE_THROW_CALL_ERROR(start_read, error_code);
 }
 
 static zend_function_entry call_methods[] = {
diff --git a/src/php/ext/grpc/call.h b/src/php/ext/grpc/call.h
index 4151c76512cd998b02396e6789590305aa118bb4..c3b18d66cb6607e44a8d959ae20f6fa979e5ad95 100755
--- a/src/php/ext/grpc/call.h
+++ b/src/php/ext/grpc/call.h
@@ -12,6 +12,17 @@
 
 #include "grpc/grpc.h"
 
+// Throw an exception if error_code is not OK
+#define MAYBE_THROW_CALL_ERROR(func_name, error_code)                   \
+  do{                                                                   \
+    if(error_code != GRPC_CALL_OK) {                                    \
+      zend_throw_exception(spl_ce_LogicException,                       \
+                           #func_name " was called incorrectly",        \
+                           (long)error_code TSRMLS_CC);                 \
+    }                                                                   \
+  } while(0)
+
+
 /* Class entry for the Call PHP class */
 zend_class_entry *grpc_ce_call;
 
diff --git a/src/php/ext/grpc/server.c b/src/php/ext/grpc/server.c
index 7e98713bd5b12751246dafda4e633710675e1c47..5af42f76ee0b3e7ac7a0faed4271afd770e8b9da 100755
--- a/src/php/ext/grpc/server.c
+++ b/src/php/ext/grpc/server.c
@@ -121,6 +121,7 @@ PHP_METHOD(Server, __construct){
  * @return Void
  */
 PHP_METHOD(Server, request_call){
+  grpc_call_error error_code;
   wrapped_grpc_server *server =
     (wrapped_grpc_server*)zend_object_store_get_object(getThis() TSRMLS_CC);
   long tag_new;
@@ -133,7 +134,8 @@ PHP_METHOD(Server, request_call){
                          1 TSRMLS_CC);
     return;
   }
-  grpc_server_request_call(server->wrapped, (void*)tag_new);
+  error_code = grpc_server_request_call(server->wrapped, (void*)tag_new);
+  MAYBE_THROW_CALL_ERROR(request_call, error_code);
 }
 
 /**
diff --git a/src/php/tests/unit_tests/CallTest.php b/src/php/tests/unit_tests/CallTest.php
index 150b8c38609706b674b6f932fa085d6fc4bb0882..253052a0382dba484d043ddf6898dbf31334632a 100755
--- a/src/php/tests/unit_tests/CallTest.php
+++ b/src/php/tests/unit_tests/CallTest.php
@@ -9,12 +9,31 @@ class CallTest extends PHPUnit_Framework_TestCase{
   }
 
   public function setUp() {
+    $this->cq = new Grpc\CompletionQueue();
     $this->channel = new Grpc\Channel('localhost:9001', []);
     $this->call = new Grpc\Call($this->channel,
                                 '/foo',
                                 Grpc\Timeval::inf_future());
   }
 
+  /**
+   * @expectedException LogicException
+   * @expectedExceptionCode Grpc\CALL_ERROR_INVALID_FLAGS
+   * @expectedExceptionMessage start_invoke
+   */
+  public function testStartInvokeRejectsBadFlags() {
+    $this->call->start_invoke($this->cq, 0, 0, 0, 0xDEADBEEF);
+  }
+
+  /**
+   * @expectedException LogicException
+   * @expectedExceptionCode Grpc\CALL_ERROR_NOT_ON_CLIENT
+   * @expectedExceptionMessage server_accept
+   */
+  public function testServerAcceptFailsCorrectly() {
+    $this->call->server_accept($this->cq, 0);
+  }
+
   /* These test methods with assertTrue(true) at the end just check that the
      method calls completed without errors. PHPUnit warns for tests with no
      asserts, and this avoids that warning without changing the meaning of the
diff --git a/src/php/tests/unit_tests/EndToEndTest.php b/src/php/tests/unit_tests/EndToEndTest.php
index e4433c83106b455fccc03875d0ad9145c3421836..3818f9531c94a3107572d1ea13be12e7393435a8 100755
--- a/src/php/tests/unit_tests/EndToEndTest.php
+++ b/src/php/tests/unit_tests/EndToEndTest.php
@@ -37,7 +37,7 @@ class EndToEndTest extends PHPUnit_Framework_TestCase{
     $this->assertNotNull($event);
     $this->assertEquals(Grpc\INVOKE_ACCEPTED, $event->type);
 
-    $this->assertEquals(Grpc\CALL_OK, $call->writes_done($tag));
+    $call->writes_done($tag);
     $event = $this->client_queue->next($deadline);
     $this->assertNotNull($event);
     $this->assertEquals(Grpc\FINISH_ACCEPTED, $event->type);
@@ -45,7 +45,7 @@ class EndToEndTest extends PHPUnit_Framework_TestCase{
 
     // check that a server rpc new was received
     $this->server->start();
-    $this->assertEquals(Grpc\CALL_OK, $this->server->request_call($server_tag));
+    $this->server->request_call($server_tag);
     $event = $this->server_queue->next($deadline);
     $this->assertNotNull($event);
     $this->assertEquals(Grpc\SERVER_RPC_NEW, $event->type);
@@ -116,14 +116,14 @@ class EndToEndTest extends PHPUnit_Framework_TestCase{
     $this->assertEquals(Grpc\INVOKE_ACCEPTED, $event->type);
 
     // the client writes
-    $this->assertEquals(Grpc\CALL_OK, $call->start_write($req_text, $tag));
+    $call->start_write($req_text, $tag);
     $event = $this->client_queue->next($deadline);
     $this->assertNotNull($event);
     $this->assertEquals(Grpc\WRITE_ACCEPTED, $event->type);
 
     // check that a server rpc new was received
     $this->server->start();
-    $this->assertEquals(Grpc\CALL_OK, $this->server->request_call($server_tag));
+    $this->server->request_call($server_tag);
     $event = $this->server_queue->next($deadline);
     $this->assertNotNull($event);
     $this->assertEquals(Grpc\SERVER_RPC_NEW, $event->type);
@@ -137,7 +137,7 @@ class EndToEndTest extends PHPUnit_Framework_TestCase{
                         $server_call->server_end_initial_metadata());
 
     // start the server read
-    $this->assertEquals(Grpc\CALL_OK, $server_call->start_read($server_tag));
+    $server_call->start_read($server_tag);
     $event = $this->server_queue->next($deadline);
     $this->assertNotNull($event);
     $this->assertEquals(Grpc\READ, $event->type);
@@ -156,14 +156,14 @@ class EndToEndTest extends PHPUnit_Framework_TestCase{
     $this->assertEquals(Grpc\CLIENT_METADATA_READ, $event->type);
 
     // the client reads the reply
-    $this->assertEquals(Grpc\CALL_OK, $call->start_read($tag));
+    $call->start_read($tag);
     $event = $this->client_queue->next($deadline);
     $this->assertNotNull($event);
     $this->assertEquals(Grpc\READ, $event->type);
     $this->assertEquals($reply_text, $event->data);
 
     // the client sends writes done
-    $this->assertEquals(Grpc\CALL_OK, $call->writes_done($tag));
+    $call->writes_done($tag);
     $event = $this->client_queue->next($deadline);
     $this->assertEquals(Grpc\FINISH_ACCEPTED, $event->type);
     $this->assertEquals(Grpc\OP_OK, $event->data);
diff --git a/src/php/tests/unit_tests/SecureEndToEndTest.php b/src/php/tests/unit_tests/SecureEndToEndTest.php
index 70fb31de1e2cba53b10d350ee8406929a840e70d..c562a821a4877e198707989512097b803a2edf6d 100755
--- a/src/php/tests/unit_tests/SecureEndToEndTest.php
+++ b/src/php/tests/unit_tests/SecureEndToEndTest.php
@@ -48,14 +48,14 @@ class SecureEndToEndTest extends PHPUnit_Framework_TestCase{
     $this->assertNotNull($event);
     $this->assertEquals(Grpc\INVOKE_ACCEPTED, $event->type);
 
-    $this->assertEquals(Grpc\CALL_OK, $call->writes_done($tag));
+    $call->writes_done($tag);
     $event = $this->client_queue->next($deadline);
     $this->assertNotNull($event);
     $this->assertEquals(Grpc\FINISH_ACCEPTED, $event->type);
     $this->assertEquals(Grpc\OP_OK, $event->data);
 
     // check that a server rpc new was received
-    $this->assertEquals(Grpc\CALL_OK, $this->server->request_call($server_tag));
+    $this->server->request_call($server_tag);
     $event = $this->server_queue->next($deadline);
     $this->assertNotNull($event);
     $this->assertEquals(Grpc\SERVER_RPC_NEW, $event->type);
@@ -126,13 +126,13 @@ class SecureEndToEndTest extends PHPUnit_Framework_TestCase{
     $this->assertEquals(Grpc\INVOKE_ACCEPTED, $event->type);
 
     // the client writes
-    $this->assertEquals(Grpc\CALL_OK, $call->start_write($req_text, $tag));
+    $call->start_write($req_text, $tag);
     $event = $this->client_queue->next($deadline);
     $this->assertNotNull($event);
     $this->assertEquals(Grpc\WRITE_ACCEPTED, $event->type);
 
     // check that a server rpc new was received
-    $this->assertEquals(Grpc\CALL_OK, $this->server->request_call($server_tag));
+    $this->server->request_call($server_tag);
     $event = $this->server_queue->next($deadline);
     $this->assertNotNull($event);
     $this->assertEquals(Grpc\SERVER_RPC_NEW, $event->type);
@@ -146,7 +146,7 @@ class SecureEndToEndTest extends PHPUnit_Framework_TestCase{
                         $server_call->server_end_initial_metadata());
 
     // start the server read
-    $this->assertEquals(Grpc\CALL_OK, $server_call->start_read($server_tag));
+    $server_call->start_read($server_tag);
     $event = $this->server_queue->next($deadline);
     $this->assertNotNull($event);
     $this->assertEquals(Grpc\READ, $event->type);
@@ -165,14 +165,14 @@ class SecureEndToEndTest extends PHPUnit_Framework_TestCase{
     $this->assertEquals(Grpc\CLIENT_METADATA_READ, $event->type);
 
     // the client reads the reply
-    $this->assertEquals(Grpc\CALL_OK, $call->start_read($tag));
+    $call->start_read($tag);
     $event = $this->client_queue->next($deadline);
     $this->assertNotNull($event);
     $this->assertEquals(Grpc\READ, $event->type);
     $this->assertEquals($reply_text, $event->data);
 
     // the client sends writes done
-    $this->assertEquals(Grpc\CALL_OK, $call->writes_done($tag));
+    $call->writes_done($tag);
     $event = $this->client_queue->next($deadline);
     $this->assertEquals(Grpc\FINISH_ACCEPTED, $event->type);
     $this->assertEquals(Grpc\OP_OK, $event->data);