Repository: basho/riak-nodejs-client
Pull request #40 (2015-04-10 18:09:15)

READY: Remove "callback" from all Joi schemas.
Having `callback` in the schema confused me several times into thinking that was a valid way to specify the callback for an operation.

This will remove that from the schema but uses `delete` to achieve the same thing within `Builder` classes.

I also nuked a bunch of end-of-line whitespace so I recommend adding `?w=1` to the URL when reviewing the diffs for this PR.


Patch:
diff --git a/lib/commands/crdt/fetchcounter.js b/lib/commands/crdt/fetchcounter.js
index 08cd4f1..3770a10 100644
--- a/lib/commands/crdt/fetchcounter.js
+++ b/lib/commands/crdt/fetchcounter.js
@@ -27,58 +27,58 @@ var Joi = require('joi');
 
 /**
  *  Command used to fetch a counter value from Riak.
- *  
+ *
  *  As a convenience, a builder class is provided:
- *      
+ *
  *      var fetch = new FetchCounter.Builder()
  *                      .withBucketType('myBucketType')
  *                      .withBucket('myBucket')
  *                      .withKey('myKey')
  *                      .withCallback(myCallback)
  *                      .build();
- *                      
+ *
  * See {{#crossLink "FetchCounter.Builder"}}FetchCounter.Builder{{/crossLink}}
- *  
+ *
  * @class FetchCounter
  * @constructor
- * @param {Object} options The options to use for this command. 
+ * @param {Object} options The options to use for this command.
  * @param {String} options.bucketType The bucket type in Riak.
  * @param {String} options.bucket The bucket in Riak.
  * @param {String} options.key The key for the counter you want to fetch.
  * @param {Number} [options.timeout] Set a timeout in Riak for this operation.
- * @param {Number} [options.r] The R value to use for this fetch. 
+ * @param {Number} [options.r] The R value to use for this fetch.
  * @param {Number} [options.pr] The PR value to use for this fetch.
  * @param {Boolean} [options.notFoundOk] If true a vnode returning notfound for a key increments the R tally.
  * @param {Boolean} [options.useBasicQuorum] Controls whether a read request should return early in some fail cases.
  * @param {Function} callback The callback to be executed when the operation completes.
  * @param {String} callback.err An error message. Will be null if no error.
- * @param {Object} callback.response The response from Riak. 
+ * @param {Object} callback.response The response from Riak.
  * @param {Number} callback.response.counterValue The counter value in Riak.
  * @param {Boolean} callback.response.notFound True if there was no counter in Riak.
- * @extends CommandBase 
+ * @extends CommandBase
  */
 function FetchCounter(options, callback) {
     CommandBase.call(this, 'DtFetchReq', 'DtFetchResp', callback);
-    
+
     var self = this;
     Joi.validate(options, schema, function(err, options) {
-       
+
         if (err) {
             throw err;
         }
-    
+
         self.options = options;
     });
-    
+
     this.remainingTries = 1;
 }
 
 inherits(FetchCounter, CommandBase);
 
 FetchCounter.prototype.constructPbRequest = function() {
-    
+
     var protobuf = this.getPbReqBuilder();
-    
+
     protobuf.setBucket(new Buffer(this.options.bucket));
     protobuf.setType(new Buffer(this.options.bucketType));
     protobuf.setKey(new Buffer(this.options.key));
@@ -87,25 +87,25 @@ FetchCounter.prototype.constructPbRequest = function() {
     protobuf.setBasicQuorum(this.options.basicQuorum);
     protobuf.setNotfoundOk(this.options.notFoundOk);
     protobuf.setTimeout(this.options.timeout);
-    
+
     return protobuf;
-    
+
 };
 
 FetchCounter.prototype.onSuccess = function(dtFetchResp) {
-  
+
     var value = null;
     var notFound = false;
     if (dtFetchResp.getValue()) {
         // sint64 is weird. You either get the zigzag encoding, or
         // you can get the actual number via the bytebuffer.
         value = dtFetchResp.value.counter_value.toNumber();
-        
+
     } else {
         notFound = true;
     }
     this._callback(null, { counterValue: value, notFound: notFound });
-    
+
     return true;
 };
 
@@ -117,31 +117,30 @@ var schema = Joi.object().keys({
    pr: Joi.number().default(null).optional(),
    notFoundOk: Joi.boolean().default(null).optional(),
    basicQuorum: Joi.boolean().default(null).optional(),
-   timeout: Joi.number().default(null).optional(),
-   callback: Joi.func().strip().optional()
+   timeout: Joi.number().default(null).optional()
 });
 
 
 /**
  * A builder for constructing FetchCounter instances.
- * 
+ *
  * Rather than having to manually construct the __options__ and instantiating
  * a FetchCounter directly, this builder may be used.
- * 
+ *
  *     var fetch = new FetchCounter.Builder()
  *                      .withBucketType('myBucketType')
  *                      .withBucket('myBucket')
  *                      .withKey('myKey')
  *                      .withCallback(myCallback)
  *                      .build();
- *       
+ *
  * @class FetchCounter.Builder
  * @constructor
  */
 function Builder() {}
 
 Builder.prototype = {
-  
+
     /**
      * Set the bucket.
      * @method withBucket
@@ -210,7 +209,7 @@ Builder.prototype = {
     /**
     * Set the basic_quorum value.
     * The parameter controls whether a read request should return early in
-    * some fail cases. 
+    * some fail cases.
     * E.g. If a quorum of nodes has already
     * returned notfound/error, don't wait around for the rest.
     * @method withBasicQuorum
@@ -251,10 +250,12 @@ Builder.prototype = {
      * @return {FetchCounter}
      */
     build : function() {
-        return new FetchCounter(this, this.callback);
+        var cb = this.callback;
+        delete this.callback;
+        return new FetchCounter(this, cb);
     }
-    
+
 };
 
 module.exports = FetchCounter;
-module.exports.Builder = Builder;
\ No newline at end of file
+module.exports.Builder = Builder;
diff --git a/lib/commands/crdt/fetchmap.js b/lib/commands/crdt/fetchmap.js
index a03997e..ddbd10b 100644
--- a/lib/commands/crdt/fetchmap.js
+++ b/lib/commands/crdt/fetchmap.js
@@ -28,18 +28,18 @@ var MapField = require('../../protobuf/riakprotobuf').getProtoFor('MapField');
 
 /**
  * Command for fetching a map from Riak.
- * 
+ *
  * As a convenience, a builder class is provided:
- * 
+ *
  *     var fetch = new FetchMap.Builder()
  *                      .withBucketType('myBucketType')
  *                      .withBucket('myBucket')
  *                      .withKey('myKey')
  *                      .withCallback(myCallback)
  *                      .build();
- *                      
- * See {{#crossLink "FetchMap.Builder"}}FetchMap.Builder{{/crossLink}} 
- *        
+ *
+ * See {{#crossLink "FetchMap.Builder"}}FetchMap.Builder{{/crossLink}}
+ *
  * @class FetchMap
  * @constructor
  * @param {Object} options The options to use for this command.
@@ -54,35 +54,35 @@ var MapField = require('../../protobuf/riakprotobuf').getProtoFor('MapField');
  * @param {Boolean} [options.useBasicQuorum] Controls whether a read request should return early in some fail cases.
  * @param {Function} callback The callback to be executed when the operation completes.
  * @param {String} callback.err An error message. Will be null if no error.
- * @param {Object} callback.response The response from Riak. 
- * @param {Buffer} callback.response.context An opaque context to be used in any subsequent modification of the map. 
- * @param {Object} callback.response.map The map in Riak, converted to a JS object. 
+ * @param {Object} callback.response The response from Riak.
+ * @param {Buffer} callback.response.context An opaque context to be used in any subsequent modification of the map.
+ * @param {Object} callback.response.map The map in Riak, converted to a JS object.
  * @param {Boolean} callback.response.notFound True if there was no map in Riak.
- * @extends CommandBase 
+ * @extends CommandBase
  * @constructor
  */
 function FetchMap(options, callback) {
     CommandBase.call(this, 'DtFetchReq', 'DtFetchResp', callback);
     var self = this;
     Joi.validate(options, schema, function(err, options) {
-       
+
         if (err) {
             throw err;
         }
-        
+
         self.options = options;
-    
+
     });
-    
+
     this.remainingTries = 1;
 }
 
 inherits(FetchMap, CommandBase);
 
 FetchMap.prototype.constructPbRequest = function() {
-    
+
     var protobuf = this.getPbReqBuilder();
-    
+
     protobuf.setBucket(new Buffer(this.options.bucket));
     protobuf.setType(new Buffer(this.options.bucketType));
     protobuf.setKey(new Buffer(this.options.key));
@@ -91,9 +91,9 @@ FetchMap.prototype.constructPbRequest = function() {
     protobuf.setBasicQuorum(this.options.basicQuorum);
     protobuf.setNotfoundOk(this.options.notFoundOk);
     protobuf.setTimeout(this.options.timeout);
-    
+
     return protobuf;
-    
+
 };
 
 FetchMap.prototype.onSuccess = function(dtFetchResp) {
@@ -123,7 +123,6 @@ var schema = Joi.object().keys({
    notFoundOk: Joi.boolean().default(null).optional(),
    basicQuorum: Joi.boolean().default(null).optional(),
    timeout: Joi.number().default(null).optional(),
-   callback: Joi.func().strip().optional(),
    setsAsBuffers: Joi.boolean().default(false).optional()
 });
 
@@ -136,24 +135,24 @@ var dtType = {
 
 /**
  * A builder for constructing FetchMap instances.
- * 
+ *
  * Rather than having to manually construct the __options__ and instantiating
  * a FetchMap directly, this builder may be used.
- * 
+ *
  *     var fetch = new FetchMap.Builder()
  *                     .withBucketType('myBucketType')
  *                     .withBucket('myBucket')
  *                     .withKey('myKey')
  *                     .withCallback(myCallback)
  *                     .build();
- *       
+ *
  * @class FetchMap.Builder
  * @constructor
  */
 function Builder() {}
 
 Builder.prototype = {
-  
+
     /**
      * Set the bucket.
      * @method withBucket
@@ -187,7 +186,7 @@ Builder.prototype = {
     /**
      * Return sets as arrays of Buffers rather than strings.
      * By default the contents of sets are converted to strings. Setting this
-     * to true will cause this not to occur and the raw bytes returned 
+     * to true will cause this not to occur and the raw bytes returned
      * as Buffer objects.
      * @method withSetsAsBuffers
      * @param {Boolean} setsAsBuffers true to not convert set contents to strings.
@@ -234,7 +233,7 @@ Builder.prototype = {
     /**
     * Set the basic_quorum value.
     * The parameter controls whether a read request should return early in
-    * some fail cases. 
+    * some fail cases.
     * E.g. If a quorum of nodes has already
     * returned notfound/error, don't wait around for the rest.
     * @method withBasicQuorum
@@ -275,20 +274,22 @@ Builder.prototype = {
      * @return {FetchMap}
      */
     build : function() {
-        return new FetchMap(this, this.callback);
+        var cb = this.callback;
+        delete this.callback;
+        return new FetchMap(this, cb);
     }
-    
+
 };
 
 module.exports = FetchMap;
 module.exports.Builder = Builder;
 
 module.exports.parsePbResponse = function(pbMapEntries, setsAsBuffers) {
-    
+
     var map = { counters: {}, sets: {}, registers: {}, flags: {}, maps: {} };
     var i, j;
     for (i = 0; i < pbMapEntries.length; i++) {
-        
+
         var mapEntry = pbMapEntries[i];
         var mapField = mapEntry.getField();
         var key = mapField.name.toString('utf8');
@@ -318,10 +319,11 @@ module.exports.parsePbResponse = function(pbMapEntries, setsAsBuffers) {
                 break;
             default:
                 break;
-                
+
         }
-        
+
     }
-    
+
     return map;
-};
\ No newline at end of file
+};
+
diff --git a/lib/commands/crdt/fetchset.js b/lib/commands/crdt/fetchset.js
index ba47ea9..bd311ea 100644
--- a/lib/commands/crdt/fetchset.js
+++ b/lib/commands/crdt/fetchset.js
@@ -26,7 +26,7 @@ var Joi = require('joi');
 
 /**
  *  Command used to fetch a set from Riak.
- *  
+ *
  *  As a convenience, a builder class is provided:
  *
  *      var fetch = new FetchSet.Builder()
@@ -35,9 +35,9 @@ var Joi = require('joi');
  *                      .withKey('myKey')
  *                      .withCallback(myCallback)
  *                      .build();
- *                      
+ *
  * See {{#crossLink "FetchSet.Builder"}}FetchSet.Builder{{/crossLink}}
- * 
+ *
  * @class FetchSet
  * @constructor
  * @param {Object} options The options to use for this command.
@@ -52,11 +52,11 @@ var Joi = require('joi');
  * @param {Boolean} [options.useBasicQuorum] Controls whether a read request should return early in some fail cases.
  * @param {Function} callback The callback to be executed when the operation completes.
  * @param {String} callback.err An error message. Will be null if no error.
- * @param {Object} callback.response The response from Riak. 
- * @param {Buffer} callback.response.context An opaque context to be used in any subsequent modification of the set. 
+ * @param {Object} callback.response The response from Riak.
+ * @param {Buffer} callback.response.context An opaque context to be used in any subsequent modification of the set.
  * @param {String[]|Buffer[]} callback.response.values An array holding the values in the set. String by default, Buffers if setsAsBuffers was used.
- * @param {Boolean} callback.response.notFound True if there was no set in Riak. 
- * @extends CommandBase 
+ * @param {Boolean} callback.response.notFound True if there was no set in Riak.
+ * @extends CommandBase
  */
 
 function FetchSet(options, callback) {
@@ -97,7 +97,7 @@ FetchSet.prototype.constructPbRequest = function() {
 };
 
 FetchSet.prototype.onSuccess = function(dtFetchResp) {
-    
+
     var response;
     var notFound = false;
     // on a "not found" the value is null
@@ -114,23 +114,21 @@ FetchSet.prototype.onSuccess = function(dtFetchResp) {
                 valuesToReturn[i] = valueBuffers[i].toString('utf8');
             }
         }
-        
+
         context = dtFetchResp.getContext() ? dtFetchResp.getContext().toBuffer() : null;
-        
+
     } else {
         valuesToReturn = [];
         notFound = true;
     }
-    
+
     response = { context: context, values: valuesToReturn, notFound: notFound };
-    
+
     this._callback(null, response);
     return true;
 };
 
 var schema = Joi.object().keys({
-    callback: Joi.func().strip().optional(),
-
     // namespace
     bucket: Joi.string().required(),
     // bucket type is required since default probably shouldn't have a
@@ -152,17 +150,17 @@ var schema = Joi.object().keys({
 
 /**
  * A builder for constructing FetchSet instances.
- * 
+ *
  * Rather than having to manually construct the __options__ and instantiating
  * a FetchSet directly, this builder may be used.
- * 
+ *
  *     var fetch = new FetchSet.Builder()
  *                      .withBucketType('myBucketType')
  *                      .withBucket('myBucket')
  *                      .withKey('myKey')
  *                      .withCallback(myCallback)
  *                      .build();
- *       
+ *
  * @class FetchSet.Builder
  * @constructor
  */
@@ -175,7 +173,9 @@ Builder.prototype = {
      * @return {FetchSet}
      */
     build: function() {
-        return new FetchSet(this, this.callback);
+        var cb = this.callback;
+        delete this.callback;
+        return new FetchSet(this, cb);
     }
 };
 
@@ -194,10 +194,10 @@ function bb(prop) {
 * Set the callback to be executed when the operation completes.
 * @method withCallback
 * @param {String} callback.err An error message. Will be null if no error.
-* @param {Object} callback.response The response from Riak. 
-* @param {Buffer} callback.response.context An opaque context to be used in any subsequent modification of the set. 
+* @param {Object} callback.response The response from Riak.
+* @param {Buffer} callback.response.context An opaque context to be used in any subsequent modification of the set.
 * @param {String[]|Buffer[]} callback.response.values An array holding the values in the set. String by default, Buffers if setsAsBuffers was used.
-* @param {Boolean} callback.response.notFound True if there was no set in Riak. 
+* @param {Boolean} callback.response.notFound True if there was no set in Riak.
 * @chainable
 */
 bb('callback');
@@ -241,7 +241,7 @@ bb('pr');
 /**
 * Return sets as arrays of Buffers rather than strings.
 * By default the contents of sets are converted to strings. Setting this
-* to true will cause this not to occur and the raw bytes returned 
+* to true will cause this not to occur and the raw bytes returned
 * as Buffer objects.
 * @method withSetsAsBuffers
 * @param {Boolean} setsAsBuffers true to not convert set contents to strings.
@@ -261,7 +261,7 @@ bb('notFoundOk');
 /**
 * Set the basic_quorum value.
 * The parameter controls whether a read request should return early in
-* some fail cases. 
+* some fail cases.
 * E.g. If a quorum of nodes has already
 * returned notfound/error, don't wait around for the rest.
 * @method withBasicQuorum
diff --git a/lib/commands/crdt/updatecounter.js b/lib/commands/crdt/updatecounter.js
index 4e51be4..73cccdd 100644
--- a/lib/commands/crdt/updatecounter.js
+++ b/lib/commands/crdt/updatecounter.js
@@ -29,9 +29,9 @@ var CounterOp = require('../../protobuf/riakprotobuf').getProtoFor('CounterOp');
 
 /**
  * Command used to update a Counter in Riak
- * 
+ *
  * As a convenience, a builder class is provided:
- * 
+ *
  *     var update = new UpdateCounter.Builder()
  *               .withBucketType('counters')
  *               .withBucket('myBucket')
@@ -39,9 +39,9 @@ var CounterOp = require('../../protobuf/riakprotobuf').getProtoFor('CounterOp');
  *               .withIncrement(100)
  *               .withCallback(callback)
  *               .build();
- *               
+ *
  * See {{#crossLink "UpdateCounter.Builder"}}UpdateCounter.Builder{{/crossLink}}
- * 
+ *
  * @module CRDT
  * @class UpdateCounter
  * @constructor
@@ -61,17 +61,17 @@ var CounterOp = require('../../protobuf/riakprotobuf').getProtoFor('CounterOp');
  * @param {Number} callback.response.counterValue The value of the counter in Riak.
  * @extends CommandBase
  */
-function UpdateCounter(options, callback) { 
+function UpdateCounter(options, callback) {
     CommandBase.call(this, 'DtUpdateReq', 'DtUpdateResp', callback);
     var self = this;
     Joi.validate(options, schema, function(err, options) {
-       
+
         if (err) {
             throw err;
         }
-    
+
         self.options = options;
-    
+
     });
     this.remainingTries = 1;
 }
@@ -79,36 +79,36 @@ function UpdateCounter(options, callback) {
 inherits(UpdateCounter, CommandBase);
 
 UpdateCounter.prototype.constructPbRequest = function() {
-    
+
     var protobuf = this.getPbReqBuilder();
-    
+
     protobuf.setBucket(new Buffer(this.options.bucket));
     protobuf.setType(new Buffer(this.options.bucketType));
-    
+
     // key can be null to have Riak generate it.
     if (this.options.key !== null) {
         protobuf.setKey(new Buffer(this.options.key));
     }
-    
+
     protobuf.setTimeout(this.options.timeout);
     protobuf.setW(this.options.w);
     protobuf.setPw(this.options.pw);
     protobuf.setDw(this.options.dw);
     protobuf.setReturnBody(this.options.returnBody);
-    
+
     var dtOp = new DtOp();
     var counterOp = new CounterOp();
     counterOp.increment = this.options.increment;
     dtOp.counter_op = counterOp;
     protobuf.setOp(dtOp);
-    
+
     return protobuf;
-    
-    
+
+
 };
 
 UpdateCounter.prototype.onSuccess = function(dtUpdateResp) {
-    
+
     // dtUpdateResp will be null if returnBody wasn't specified
     if (dtUpdateResp) {
         var key = null;
@@ -125,7 +125,7 @@ UpdateCounter.prototype.onSuccess = function(dtUpdateResp) {
     } else {
         this._callback(null, null);
     }
-    
+
 };
 
 var schema = Joi.object().keys({
@@ -133,7 +133,6 @@ var schema = Joi.object().keys({
     bucketType: Joi.string().required(),
     key: Joi.string().default(null).optional(),
     increment: Joi.number().required(),
-    callback: Joi.func().strip().optional(),
     w: Joi.number().default(null).optional(),
     dw: Joi.number().default(null).optional(),
     pw: Joi.number().default(null).optional(),
@@ -141,14 +140,12 @@ var schema = Joi.object().keys({
     timeout: Joi.number().default(null).optional()
 });
 
-
-
 /**
  * A builder for constructing UpdateCounter instances.
- * 
+ *
  * Rather than having to manually construct the __options__ and instantiating
  * a UpdateCounter directly, this builder may be used.
- * 
+ *
  *     var update = new UpdateCounter.Builder()
  *               .withBucketType('counters')
  *               .withBucket('myBucket')
@@ -156,14 +153,14 @@ var schema = Joi.object().keys({
  *               .withIncrement(100)
  *               .withCallback(callback)
  *               .build();
- *       
+ *
  * @class UpdateCounter.Builder
  * @constructor
  */
 function Builder() {}
 
 Builder.prototype = {
-  
+
     /**
      * Set the bucket.
      * @method withBucket
@@ -176,7 +173,7 @@ Builder.prototype = {
     },
     /**
      * Set the bucket type.
-     * 
+     *
      * @method withBucketType
      * @param {String} bucketType the bucket type in riak
      * @chainable
@@ -187,7 +184,7 @@ Builder.prototype = {
     },
     /**
      * Set the key.
-     * If not set Riak will generate one. 
+     * If not set Riak will generate one.
      * @method withKey
      * @param {String} key the key in riak.
      * @chainable
@@ -246,7 +243,7 @@ Builder.prototype = {
     /**
     * Return the counter after updating.
     * @method withReturnBody
-    * @param {boolean} returnBody true to return the counter. 
+    * @param {boolean} returnBody true to return the counter.
     * @chainable
     */
     withReturnBody: function(returnBody) {
@@ -283,9 +280,12 @@ Builder.prototype = {
      * @return {UpdateCounter} a UpdateCounter instance
      */
     build : function() {
-        return new UpdateCounter(this, this.callback);
+        var cb = this.callback;
+        delete this.callback;
+        return new UpdateCounter(this, cb);
     }
 };
 
 module.exports = UpdateCounter;
 module.exports.Builder = Builder;
+
diff --git a/lib/commands/crdt/updatemap.js b/lib/commands/crdt/updatemap.js
index dfa6bb5..ed6a0d6 100644
--- a/lib/commands/crdt/updatemap.js
+++ b/lib/commands/crdt/updatemap.js
@@ -34,10 +34,10 @@ var FetchMap = require('./fetchmap');
 
 /**
  * Command used to update a Map in Riak.
- * 
- * As a convenience, a builder method is provided as well as an object with 
+ *
+ * As a convenience, a builder method is provided as well as an object with
  * a fluent API for constructing the update.
- * 
+ *
  *     var mapOp = new UpdateMap.MapOperation();
  *     mapOp.incrementCounter('counter_1', 50)
  *         .addToSet('set_1', 'set_value_1')
@@ -46,9 +46,9 @@ var FetchMap = require('./fetchmap');
  *         .map('inner_map')
  *             .incrementCounter('counter_1', 50)
  *             .addToSet('set_2', 'set_value_2');
- *         
+ *
  * See {{#crossLink "UpdateMap.MapOperation"}}UpdateMap.MapOperation{{/crossLink}}
- *         
+ *
  *     var update = new UpdateMap.Builder()
  *               .withBucketType('maps')
  *               .withBucket('myBucket')
@@ -77,63 +77,63 @@ var FetchMap = require('./fetchmap');
  * @param {String} callback.err An error message. Will be null if no error.
  * @param {Object} callback.response The response from Riak. Will be null if returnBody is not set.
  * @param {String} callback.response.generatedKey If no key was supplied, Riak will generate and return one here.
- * @param {Buffer} callback.response.context An opaque context to be used in any subsequent modification of the map.  
- * @param {Object} callback.response.map The map in Riak, converted to a JS object. 
+ * @param {Buffer} callback.response.context An opaque context to be used in any subsequent modification of the map.
+ * @param {Object} callback.response.map The map in Riak, converted to a JS object.
  * @extends CommandBase
  */
 function UpdateMap(options, callback) {
     CommandBase.call(this, 'DtUpdateReq', 'DtUpdateResp', callback);
     var self = this;
     Joi.validate(options, schema, function(err, options) {
-       
+
         if (err) {
             throw err;
         }
-        
+
         if (options.op._hasRemoves() && options.context === null) {
             throw 'When doing any removes a context must be provided.';
         }
-    
+
         self.options = options;
-    
+
     });
-    
+
     this.remainingTries = 1;
 }
 
 inherits(UpdateMap, CommandBase);
 
 UpdateMap.prototype.constructPbRequest = function() {
-  
+
     var protobuf = this.getPbReqBuilder();
-    
+
     protobuf.setBucket(new Buffer(this.options.bucket));
     protobuf.setType(new Buffer(this.options.bucketType));
     // key can be null to have Riak generate it.
     if (this.options.key !== null) {
         protobuf.setKey(new Buffer(this.options.key));
     }
-    
+
     protobuf.setTimeout(this.options.timeout);
     protobuf.setW(this.options.w);
     protobuf.setPw(this.options.pw);
     protobuf.setDw(this.options.dw);
     protobuf.setReturnBody(this.options.returnBody);
-    
+
     protobuf.setContext(this.options.context);
-    
+
     var dtOp = new DtOp();
-    
+
     var pbMapOp = new MapOp();
-    
+
     this._populate(this.options.op, pbMapOp);
-    
+
     dtOp.setMapOp(pbMapOp);
-    
+
     protobuf.setOp(dtOp);
-    
+
     return protobuf;
-    
+
 };
 
 UpdateMap.prototype.onSuccess = function(dtUpdateResp) {
@@ -148,11 +148,11 @@ UpdateMap.prototype.onSuccess = function(dtUpdateResp) {
         response = { generatedKey: key,
                 context: dtUpdateResp.getContext().toBuffer(),
                 map: FetchMap.parsePbResponse(dtUpdateResp.map_value, this.options.setsAsBuffers) };
-        
+
     }
     this._callback(null, response);
     return true;
-    
+
 };
 
 UpdateMap.prototype._populate = function(mapOp, pbMapOp) {
@@ -191,7 +191,7 @@ UpdateMap.prototype._populate = function(mapOp, pbMapOp) {
             pbMapOp.removes.push(field);
         }
     }
-    
+
     for (i = 0; i < mapOp.counters.increment.length; i++) {
         update = new MapUpdate();
         field = new MapField();
@@ -246,7 +246,7 @@ UpdateMap.prototype._populate = function(mapOp, pbMapOp) {
         update.setField(field);
         update.setRegisterOp(mapOp.registers.set[i].value);
         pbMapOp.updates.push(update);
-    } 
+    }
     for (i = 0; i < mapOp.flags.set.length; i++) {
         update = new MapUpdate();
         field = new MapField();
@@ -259,7 +259,7 @@ UpdateMap.prototype._populate = function(mapOp, pbMapOp) {
             update.setFlagOp(MapUpdate.FlagOp.DISABLE);
         }
         pbMapOp.updates.push(update);
-    } 
+    }
     for (i = 0; i < mapOp.maps.modify.length; i++) {
         update = new MapUpdate();
         field = new MapField();
@@ -277,7 +277,6 @@ var schema = Joi.object().keys({
     bucket: Joi.string().required(),
     bucketType: Joi.string().required(),
     key: Joi.string().optional(),
-    callback: Joi.func().required(),
     op: Joi.object().type(MapOperation).required(),
     w: Joi.number().default(null).optional(),
     dw: Joi.number().default(null).optional(),
@@ -285,16 +284,16 @@ var schema = Joi.object().keys({
     returnBody: Joi.boolean().default(true).optional(),
     setsAsBuffers: Joi.boolean().default(false).optional(),
     timeout: Joi.number().default(null).optional(),
-    context: Joi.binary().default(null).optional()    
+    context: Joi.binary().default(null).optional()
 });
 
 
 /**
  * A builder for constructing UpdateMap instances.
- * 
+ *
  * Rather than having to manually construct the __options__ and instantiating
  * a UpdateMap directly, this builder may be used.
- * 
+ *
  *     var update = new UpdateMap.Builder()
  *               .withBucketType('counters')
  *               .withBucket('myBucket')
@@ -302,16 +301,16 @@ var schema = Joi.object().keys({
  *               .withMapOperation(mapOp)
  *               .withCallback(callback)
  *               .build();
- *       
+ *
  * See {{#crossLink "UpdateMap.MapOperation"}}UpdateMap.MapOperation{{/crossLink}}
- *       
+ *
  * @class UpdateMap.Builder
  * @constructor
  */
 function Builder() {}
 
 Builder.prototype = {
-  
+
     /**
      * Set the bucket.
      * @method withBucket
@@ -371,8 +370,8 @@ Builder.prototype = {
      * @param {String} callback.err An error message. Will be null if no error.
      * @param {Object} callback.response The response from Riak. Will be null if returnBody is not set.
      * @param {String} callback.response.generatedKey If no key was supplied, Riak will generate and return one here.
-     * @param {Buffer} callback.response.context An opaque context to be used in any subsequent modification of the map.  
-     * @param {Object} callback.response.map The map in Riak, converted to a JS object. 
+     * @param {Buffer} callback.response.context An opaque context to be used in any subsequent modification of the map.
+     * @param {Object} callback.response.map The map in Riak, converted to a JS object.
      * @chainable
      */
     withCallback : function(callback) {
@@ -418,7 +417,7 @@ Builder.prototype = {
     /**
     * Return the counter after updating.
     * @method withReturnBody
-    * @param {boolean} returnBody true to return the counter. 
+    * @param {boolean} returnBody true to return the counter.
     * @chainable
     */
     withReturnBody: function(returnBody) {
@@ -428,7 +427,7 @@ Builder.prototype = {
     /**
      * Return sets as arrays of Buffers rather than strings.
      * By default the contents of sets are converted to strings. Setting this
-     * to true will cause this not to occur and the raw bytes returned 
+     * to true will cause this not to occur and the raw bytes returned
      * as Buffer objects. Note this is only used with the returnBody option.
      * @method withSetsAsBuffers
      * @param {Boolean} setsAsBuffers true to not convert set contents to strings.
@@ -454,16 +453,18 @@ Builder.prototype = {
      * @return {UpdateMap}
      */
     build : function() {
-        return new UpdateMap(this, this.callback);
+        var cb = this.callback;
+        delete this.callback;
+        return new UpdateMap(this, cb);
     }
-    
+
 };
 
 /**
  * Class that encapsulates modifications to a Map in Riak.
- * 
+ *
  * Rather than manually constructing this yourself, a fluent API is provided.
- * 
+ *
  *     var mapOp = new UpdateMap.MapOperation();
  *     mapOp.incrementCounter('counter_1', 50)
  *         .addToSet('set_1', 'set_value_1')
@@ -472,12 +473,12 @@ Builder.prototype = {
  *         .map('inner_map')
  *             .incrementCounter('counter_1', 50)
  *             .addToSet('set_2', 'set_value_2');
- *             
+ *
  * @class UpdateMap.MapOperation
  * @constructor
  */
 function MapOperation() {
-    
+
     this.counters = { increment: [], remove : []};
     this.maps = { modify: [], remove: []};
     this.sets = { adds: [], removes: [], remove: []};
@@ -486,12 +487,12 @@ function MapOperation() {
 }
 
 MapOperation.prototype = {
-  
+
     /**
-     * Increment (and/or create) a counter inside the map. 
+     * Increment (and/or create) a counter inside the map.
      * @method incrementCounter
      * @param {String} key the key in the map for this counter.
-     * @param {Number} increment the amount to increment (or decrement if negative) 
+     * @param {Number} increment the amount to increment (or decrement if negative)
      * @chainable
      */
     incrementCounter : function(key, increment) {
@@ -499,7 +500,7 @@ MapOperation.prototype = {
         var op = this._getOp(this.counters.increment, key);
         if (op) {
             op.increment += increment;
-        } else { 
+        } else {
             this.counters.increment.push({key: key, increment: increment});
         }
         return this;
@@ -628,9 +629,9 @@ MapOperation.prototype = {
     /**
      * Access/create a map inside the current one.
      * This adds/accesses a nested map and returns a reference to another
-     * MapOperation that applies to it. You can then modify the componets of 
+     * MapOperation that applies to it. You can then modify the componets of
      * that map;
-     * 
+     *
      *     mapOp.map('inner_map')
      *         .incrementCounter('counter_1', 50)
      *         .addToSet('set_2', 'set_value_2');
@@ -685,12 +686,12 @@ MapOperation.prototype = {
         return null;
     },
     _hasRemoves : function() {
-        
+
         var nestedHaveRemoves = false;
         for (var i = 0; i < this.maps.modify.length; i++) {
             nestedHaveRemoves |= this.maps.modify[i].map._hasRemoves();
         }
-        
+
         return nestedHaveRemoves ||
                 this.counters.remove.length ||
                 this.maps.remove.length ||
@@ -699,9 +700,10 @@ MapOperation.prototype = {
                 this.registers.remove.length ||
                 this.flags.remove.length;
     }
-    
+
 };
 
 module.exports = UpdateMap;
 module.exports.MapOperation = MapOperation;
 module.exports.Builder = Builder;
+
diff --git a/lib/commands/crdt/updateset.js b/lib/commands/crdt/updateset.js
index 5625088..63e1c70 100644
--- a/lib/commands/crdt/updateset.js
+++ b/lib/commands/crdt/updateset.js
@@ -32,9 +32,9 @@ var SetOp = Rpb.getProtoFor('SetOp');
 
 /**
  * Command used tp update a set in Riak
- * 
+ *
  * As a convenience, a builder class is provided:
- * 
+ *
  *        var update = new UpdateSet.Builder()
  *               .withBucketType('sets')
  *               .withBucket('myBucket')
@@ -42,7 +42,7 @@ var SetOp = Rpb.getProtoFor('SetOp');
  *               .withAdditions(['this', 'that', 'other'])
  *               .withCallback(callback)
  *               .build();
- *               
+ *
  * See {{#crossLink "UpdateSet.Builder"}}UpdateSet.Builder{{/crossLink}}
  * @class UpdateSet
  * @constructor
@@ -63,7 +63,7 @@ var SetOp = Rpb.getProtoFor('SetOp');
  * @param {String} callback.err An error message. Will ne null if no error.
  * @param {Object} callback.response The response from Riak. will be null if returnBody is not set.
  * @param {String} callback.response.generatedKey If no key was supplied, Riak will generate and return one here.
- * @param {Buffer} callback.response.context An opaque context to be used in any subsequent modification of the set. 
+ * @param {Buffer} callback.response.context An opaque context to be used in any subsequent modification of the set.
  * @param {String[]|Buffer[]} callback.response.values An array holding the values in the set. String by default, Buffers if setsAsBuffers was used.
  * @extends CommandBase
  */
@@ -109,11 +109,11 @@ UpdateSet.prototype.constructPbRequest = function() {
     // namespace
     protobuf.setType(pbuf(this, 'bucketType'));
     protobuf.setBucket(pbuf(this, 'bucket'));
-    
+
     if (this.options.key) {
         protobuf.setKey(pbuf(this, 'key'));
     }
-    
+
     // operation
     var op = new DtOp();
     protobuf.setOp(op);
@@ -137,14 +137,14 @@ UpdateSet.prototype.constructPbRequest = function() {
 
 UpdateSet.prototype.onSuccess = function(dtUpdateResp) {
     var response = null;
-    
+
     // dtUpdateResp will be null if returnBody is not set
     if (dtUpdateResp) {
         var key = null;
         if (dtUpdateResp.getKey()) {
             key = dtUpdateResp.getKey().toString('utf8');
         }
-        
+
         var valuesToReturn = new Array(dtUpdateResp.set_value.length);
         var i;
         for (i = 0; i < dtUpdateResp.set_value.length; i++) {
@@ -154,7 +154,7 @@ UpdateSet.prototype.onSuccess = function(dtUpdateResp) {
                 valuesToReturn[i] = dtUpdateResp.set_value[i].toString('utf8');
             }
         }
-        
+
         response = { generatedKey: key,
                 context: dtUpdateResp.getContext() ? dtUpdateResp.getContext().toBuffer() : null,
                 values: valuesToReturn };
@@ -164,8 +164,6 @@ UpdateSet.prototype.onSuccess = function(dtUpdateResp) {
 };
 
 var schema = Joi.object().keys({
-    callback: Joi.func().strip().optional(),
-
     //namespace
     bucket: Joi.string().required(),
     // bucket type is required since default probably shouldn't have a
@@ -193,7 +191,7 @@ var schema = Joi.object().keys({
 
 /**
  * A builder for constructing UpdateSet instances.
- * 
+ *
  * Rather than having to manually construct the __options__ and instantiating
  * a UpdateSet directly, this builder may be used.
  *
@@ -217,7 +215,9 @@ Builder.prototype = {
      * @return {UpdateSet}
      */
     build: function() {
-        return new UpdateSet(this, this.callback);
+        var cb = this.callback;
+        delete this.callback;
+        return new UpdateSet(this, cb);
     }
 };
 
@@ -238,7 +238,7 @@ function bb(prop) {
  * @param {String} callback.err An error message. Will ne null if no error.
  * @param {Object} callback.response The response from Riak. will be null if returnBody is not set.
  * @param {String} callback.response.generatedKey If no key was supplied, Riak will generate and return one here.
- * @param {Buffer} callback.response.context An opaque context to be used in any subsequent modification of the set. 
+ * @param {Buffer} callback.response.context An opaque context to be used in any subsequent modification of the set.
  * @param {String[]|Buffer[]} callback.response.values An array holding the values in the set. String by default, Buffers if setsAsBuffers was used.
  */
 bb('callback');
@@ -275,7 +275,7 @@ bb('context');
 /**
 * Return sets as arrays of Buffers rather than strings.
 * By default the contents of sets are converted to strings. Setting this
-* to true will cause this not to occur and the raw bytes returned 
+* to true will cause this not to occur and the raw bytes returned
 * as Buffer objects.
 * @method withSetsAsBuffers
 * @param {Boolean} setsAsBuffers true to not convert set contents to strings.
@@ -336,7 +336,7 @@ bb('timeout');
 /**
  * The values you wish to add to this set.
  * @method withAdditions
- * @param {String[]|Buffer[]} additions The values to add. 
+ * @param {String[]|Buffer[]} additions The values to add.
  * @chainable
  */
 bb('additions');
diff --git a/lib/commands/kv/deletevalue.js b/lib/commands/kv/deletevalue.js
index 047cfd3..42a9054 100644
--- a/lib/commands/kv/deletevalue.js
+++ b/lib/commands/kv/deletevalue.js
@@ -26,16 +26,16 @@ var Joi = require('joi');
 
 /**
  * Command used to delete a value from Riak.
- * 
+ *
  * As a convenience, a builder class is provided:
- * 
+ *
  *      var deleteValue = new DeleteValue.Builder()
  *          .withBucket('myBucket')
  *          .withKey('myKey')
  *          .withVClock(vclock)
  *          .withCallback(callback)
  *          .build();
- * 
+ *
  * See {{#crossLink "DeleteValue.Builder"}}DeleteValue.Builder{{/crossLink}}
  * @class DeleteValue
  * @constructor
@@ -60,15 +60,15 @@ function DeleteValue(options, callback) {
     CommandBase.call(this, 'RpbDelReq', 'RpbDelResp', callback);
     var self = this;
     Joi.validate(options, schema, function(err, options) {
-       
+
         if (err) {
             throw err;
         }
-    
+
         self.options = options;
-    
+
     });
-    
+
     this.remainingRetries = 1;
 }
 
@@ -77,51 +77,51 @@ function DeleteValue(options, callback) {
 inherits(DeleteValue, CommandBase);
 
 DeleteValue.prototype.constructPbRequest = function() {
-    
+
     var protobuf = this.getPbReqBuilder();
-    
+
     protobuf.setBucket(new Buffer(this.options.bucket));
     protobuf.setType(new Buffer(this.options.bucketType));
     protobuf.setKey(new Buffer(this.options.key));
-    
+
     if (this.options.hasOwnProperty('vclock')) {
         protobuf.setVclock(this.options.vclock);
     }
-    
+
     if (this.options.hasOwnProperty('w')) {
         protobuf.setW(this.options.w);
     }
-    
+
     if (this.options.hasOwnProperty('dw')) {
         protobuf.setDw(this.options.dw);
     }
-    
+
     if (this.options.hasOwnProperty('pw')) {
         protobuf.setPw(this.options.pw);
     }
-    
+
     if (this.options.hasOwnProperty('r')) {
         protobuf.setR(this.options.r);
     }
     if (this.options.hasOwnProperty('pr')) {
         protobuf.setPr(this.options.pr);
     }
-    
+
     if (this.options.hasOwnProperty('rw')) {
         protobuf.setRw(this.options.rw);
     }
-    
+
     if (this.options.hasOwnProperty('timeout')) {
         protobuf.setTimeout(this.options.timeout);
     }
-    
+
     return protobuf;
-    
+
 };
 
 DeleteValue.prototype.onSuccess = function(rpbGetResp) {
 
-    // There is no body to a RpbDelResp. RpbDelReq either 
+    // There is no body to a RpbDelResp. RpbDelReq either
     // succeeds or returns an error. rpbDelResp will always be null
     this._callback(null, true);
     return true;
@@ -139,32 +139,31 @@ var schema = Joi.object().keys({
     pw: Joi.number().optional(),
     rw: Joi.number().optional(),
     timeout: Joi.number().default(null),
-    callback: Joi.func().strip().optional(),
     vclock: Joi.binary().optional()
 });
 
 /**
  * A builder for constructing DeleteValue instances.
- * 
+ *
  * Rather than having to manually construct the __options__ and instantiating
  * a DeleteValue directly, this builder may be used.
- * 
+ *
  *     var deleteValue = new DeleteValue.Builder()
  *          .withBucket('myBucket')
  *          .withKey('myKey')
  *          .withVClock(vclock)
  *          .withCallback(callback)
  *          .build();
- *       
+ *
  * @class DeleteValue.Builder
  * @constructor
  */
 function Builder() {
-    
+
 }
 
-Builder.prototype = { 
-  
+Builder.prototype = {
+
     /**
      * Set the bucket.
      * @method withBucket
@@ -284,7 +283,7 @@ Builder.prototype = {
         this.timeout = timeout;
         return this;
     },
-    
+
     /**
      * Set the callback to be executed when the operation completes.
      * @method withCallback
@@ -303,7 +302,9 @@ Builder.prototype = {
      * @return {DeleteValue} an instance of DeleteValue
      */
     build : function() {
-        return new DeleteValue(this, this.callback);
+        var cb = this.callback;
+        delete this.callback;
+        return new DeleteValue(this, cb);
     }
 };
 
diff --git a/lib/commands/kv/fetchbucketprops.js b/lib/commands/kv/fetchbucketprops.js
index 89bb4e1..c805115 100644
--- a/lib/commands/kv/fetchbucketprops.js
+++ b/lib/commands/kv/fetchbucketprops.js
@@ -26,15 +26,15 @@ var Joi = require('joi');
 
 /**
  * Command used to fetch a bucket's properties from Riak.
- * 
+ *
  * As a convenience, a builder class is provided:
- * 
+ *
  *     var fetch = new FetchBucketProps.Builder()
  *         .withBucketType('my_type')
  *         .withBucket('myBucket')
  *         .withCallback(myCallback)
  *         .build();
- *         
+ *
  * See {{#crossLink "FetchBucketProps.Builder"}}FetchBucketProps.Builder{{/crossLink}}
  * @class FetchBucketProps
  * @constructor
@@ -47,18 +47,18 @@ var Joi = require('joi');
  * @extends CommandBase
  */
 function FetchBucketProps(options, callback) {
-    
+
     CommandBase.call(this, 'RpbGetBucketReq','RpbGetBucketResp', callback);
     var self = this;
     Joi.validate(options, schema, function(err, options) {
-       
+
         if (err) {
             throw err;
         }
-    
+
         self.options = options;
     });
-        
+
     this.remainingTries = 1;
 
 }
@@ -66,22 +66,22 @@ function FetchBucketProps(options, callback) {
 inherits(FetchBucketProps, CommandBase);
 
 FetchBucketProps.prototype.constructPbRequest = function() {
-  
+
     var protobuf = this.getPbReqBuilder();
-    
+
     protobuf.setType(new Buffer(this.options.bucketType));
     protobuf.setBucket(new Buffer(this.options.bucket));
-    
+
     return protobuf;
-    
+
 };
 
 FetchBucketProps.prototype.onSuccess = function(rpbGetBucketResp) {
-    
+
     var rpbBucketProps = rpbGetBucketResp.getProps();
-    
+
     var bucketProps  = {
-        
+
         nVal : rpbBucketProps.getNVal(),
         allowMult : rpbBucketProps.getAllowMult(),
         lastWriteWins: rpbBucketProps.getLastWriteWins(),
@@ -103,49 +103,49 @@ FetchBucketProps.prototype.onSuccess = function(rpbGetBucketResp) {
         consistent: rpbBucketProps.getConsistent(),
         repl: rpbBucketProps.getRepl()
     };
-    
+
     var backend;
     if ((backend = rpbBucketProps.getBackend()) !== null) {
         bucketProps.backend = backend.toString('utf8');
     }
-    
+
     var searchIndex;
     if ((searchIndex = rpbBucketProps.getSearchIndex()) !== null) {
         bucketProps.searchIndex = searchIndex.toString('utf8');
     }
-    
+
     var dataType;
     if ((dataType = rpbBucketProps.getDatatype()) !== null) {
         bucketProps.dataType = dataType.toString('utf8');
     }
-    
+
     if (rpbBucketProps.getHasPrecommit()) {
         bucketProps.precommit = this._parseHooks(rpbBucketProps.getPrecommit());
     } else {
         bucketProps.precommit = [];
     }
-    
+
     if (rpbBucketProps.getHasPostcommit()) {
         bucketProps.postcommit = this._parseHooks(rpbBucketProps.getPostcommit());
     } else {
         bucketProps.postcommit = [];
     }
-    
+
     var chashKeyFun;
     if ((chashKeyFun = rpbBucketProps.getChashKeyfun()) !== null) {
         bucketProps.chashKeyfun = { mod: chashKeyFun.module.toString('utf8'),
             fun: chashKeyFun.function.toString('utf8') };
     }
-    
+
     var linkfun;
     if ((linkfun = rpbBucketProps.getLinkfun()) !== null) {
         bucketProps.linkFun = { mod: linkfun.module.toString('utf8'),
             fun: linkfun.function.toString('utf8') };
     }
-    
+
     this._callback(null, bucketProps);
     return true;
-    
+
 };
 
 FetchBucketProps.prototype._parseHooks = function(rpbCommitHooks) {
@@ -154,23 +154,22 @@ FetchBucketProps.prototype._parseHooks = function(rpbCommitHooks) {
         if (rpbCommitHooks[i].name) {
             hooks[i] = { name: rpbCommitHooks[i].name.toString('utf8') };
         } else {
-            hooks[i] = { mod: rpbCommitHooks[i].modfun.module.toString('utf8'), 
+            hooks[i] = { mod: rpbCommitHooks[i].modfun.module.toString('utf8'),
                 fun: rpbCommitHooks[i].modfun.function.toString('utf8') };
         }
     }
     return hooks;
-    
+
 };
 
 var schema = Joi.object().keys({
    bucket: Joi.string().required(),
-   bucketType: Joi.string().default('default'),
-   callback: Joi.func().strip().optional()
+   bucketType: Joi.string().default('default')
 });
 
 /**
  * A builder for constructing GetBucketProps instances
- * 
+ *
  * Rather than having to manually construct the __options__ and instantiating
  * a FetchBucketProps directly, this builder may be used.
  *
@@ -181,7 +180,7 @@ var schema = Joi.object().keys({
  *         .build();
  *
  * @class FetchBucketProps.Builder
- * @constructor 
+ * @constructor
  */
 function Builder() {}
 
@@ -225,7 +224,9 @@ Builder.prototype = {
      * @return {FetchBucketProps}
      */
     build : function() {
-        return new FetchBucketProps(this, this.callback);
+        var cb = this.callback;
+        delete this.callback;
+        return new FetchBucketProps(this, cb);
     }
 };
 
diff --git a/lib/commands/kv/fetchvalue.js b/lib/commands/kv/fetchvalue.js
index ed230a6..1e801c8 100644
--- a/lib/commands/kv/fetchvalue.js
+++ b/lib/commands/kv/fetchvalue.js
@@ -28,24 +28,24 @@ var Joi = require('joi');
 
 /**
  * Command used to fetch an object from Riak.
- * 
+ *
  * As a convenience, a builder class is provided:
- * 
+ *
  *     var fetch = new FetchValue.Builder()
  *         .withBucket('myBucket')
  *         .withKey('myKey')
  *         .withCallback(myCallback)
  *         .build();
- *      
+ *
  * See {{#crossLink "FetchValue.Builder"}}FetchValue.Builder{{/crossLink}}
- * 
+ *
  * @class FetchValue
  * @constructor
  * @param {Object} options The options for this command.
  * @param {String} [options.bucketType=default] The bucket type in riak. If not supplied 'default' is used.
  * @param {String} options.bucket The bucket in riak.
  * @param {String} options.key The key for the object you want to fetch.
- * @param {Boolean} [options.convertToJs=false] Convert the values stored in riak to a JS object using JSON.parse() 
+ * @param {Boolean} [options.convertToJs=false] Convert the values stored in riak to a JS object using JSON.parse()
  * @param {Function} [options.conflictResolver] A function used to resolve siblings to a single object.
  * @param {RiakObject[]|Object[]} options.conflictResolver.objects The array of objects returned from Riak.
  * @param {Number} [options.timeout] Set a timeout for this operation.
@@ -55,7 +55,7 @@ var Joi = require('joi');
  * @param {Boolean} [options.useBasicQuorum] Controls whether a read request should return early in some fail cases.
  * @param {Boolean} [options.returnDeletedVClock] True to return tombstones.
  * @param {Boolean} [options.headOnly] Return only the metadata.
- * @param {Buffer} [options.ifNotModified] Do not return the object if the supplied vclock matches. 
+ * @param {Buffer} [options.ifNotModified] Do not return the object if the supplied vclock matches.
  * @param {Function} callback The callback to be executed when the operation completes.
  * @param {String} callback.err An error message. Will ne null if no error.
  * @param {Object} callback.response the response from Riak.
@@ -64,22 +64,22 @@ var Joi = require('joi');
  * @param {Buffer} callback.response.vclock The vector clock for this object (and its siblings)
  * @param {Object[]|RiakObject[]} callback.response.values An array of one or more values. Either RiakObjects or JS objects if convertToJs was used.
  * @extends CommandBase
- * 
- */ 
+ *
+ */
 function FetchValue(options, callback) {
-    
+
     CommandBase.call(this, 'RpbGetReq', 'RpbGetResp', callback);
-    
+
     var self = this;
     Joi.validate(options, schema, function(err, options) {
-       
+
         if (err) {
             throw err;
         }
-    
+
         self.options = options;
     });
-    
+
     this.streaming = false;
     this.remainingTries = 1;
 }
@@ -87,9 +87,9 @@ function FetchValue(options, callback) {
 inherits(FetchValue, CommandBase);
 
 FetchValue.prototype.constructPbRequest = function() {
-    
+
     var protobuf = this.getPbReqBuilder();
-    
+
     protobuf.setBucket(new Buffer(this.options.bucket));
     protobuf.setType(new Buffer(this.options.bucketType));
     protobuf.setKey(new Buffer(this.options.key));
@@ -102,15 +102,15 @@ FetchValue.prototype.constructPbRequest = function() {
     protobuf.setHead(this.options.headOnly);
     protobuf.setIfModified(this.options.ifNotModified);
     protobuf.setTimeout(this.options.timeout);
-    
+
     return protobuf;
 
 };
 
 FetchValue.prototype.onSuccess = function(rpbGetResp) {
-        
-    // If the response is null ... it means not found. Riak only sends 
-    // a message code and zero bytes when that's the case. 
+
+    // If the response is null ... it means not found. Riak only sends
+    // a message code and zero bytes when that's the case.
     // Because that makes sense!
     var response;
     if (rpbGetResp) {
@@ -131,7 +131,7 @@ FetchValue.prototype.onSuccess = function(rpbGetResp) {
             riakObject.bucket = this.bucket;
             riakObject.bucketType = this.bucketType;
 
-            response = { isNotFound : false, isUnchanged : unchanged, vclock: vclock, values : [riakObject] }; 
+            response = { isNotFound : false, isUnchanged : unchanged, vclock: vclock, values : [riakObject] };
 
         } else {
 
@@ -151,18 +151,18 @@ FetchValue.prototype.onSuccess = function(rpbGetResp) {
             if (this.options.conflictResolver) {
                 values = [this.options.conflictResolver(values)];
             }
-            
-            response = { isNotFound: false, isUnchanged: unchanged, vclock: vclock, values: values };                        
+
+            response = { isNotFound: false, isUnchanged: unchanged, vclock: vclock, values: values };
         }
     } else {
         response = { isNotFound: true, isUnchanged: false, vclock: null, values: [] };
     }
-    
+
     this._callback(null, response);
-    
+
     return true;
 };
-    
+
 var schema = Joi.object().keys({
    bucket: Joi.string().required(),
    bucketType: Joi.string().default('default'),
@@ -176,28 +176,27 @@ var schema = Joi.object().keys({
    ifNotModified: Joi.binary().default(null).optional(),
    timeout: Joi.number().default(null).optional(),
    conflictResolver: Joi.func().default(null).optional(),
-   convertToJs: Joi.boolean().default(false).optional(),
-   callback: Joi.func().strip().optional()
+   convertToJs: Joi.boolean().default(false).optional()
 });
 
 /**
  * A builder for constructing FetchValue instances.
- * 
+ *
  * Rather than having to manually construct the __options__ and instantiating
  * a FetchValue directly, this builder may be used.
- * 
+ *
  *     var fetchValue = new FetchValue.Builder()
  *          .withBucket('myBucket')
  *          .withKey('myKey')
  *          .build();
- *       
+ *
  * @class FetchValue.Builder
  * @constructor
  */
 function Builder() {}
 
 Builder.prototype = {
-  
+
     /**
      * Set the bucket.
      * @method withBucket
@@ -267,7 +266,7 @@ Builder.prototype = {
     /**
     * Set the basic_quorum value.
     * The parameter controls whether a read request should return early in
-    * some fail cases. 
+    * some fail cases.
     * E.g. If a quorum of nodes has already
     * returned notfound/error, don't wait around for the rest.
     * @method withBasicQuorum
@@ -293,7 +292,7 @@ Builder.prototype = {
     * Causes Riak to only return the metadata for the object. The value
     * will be asSet to null.
     * @method withHeadOnly
-    * @param {Boolean} headOnly true to return only metadata. 
+    * @param {Boolean} headOnly true to return only metadata.
     * @chainable
     */
     withHeadOnly : function(headOnly) {
@@ -301,7 +300,7 @@ Builder.prototype = {
         return this;
     },
     /**
-    * Do not return the object if the supplied vclock matches. 
+    * Do not return the object if the supplied vclock matches.
     * @method withIfNotModified
     * @param {Buffer} vclock the vclock to match on
     * @chainable
@@ -320,7 +319,7 @@ Builder.prototype = {
         this.timeout = timeout;
         return this;
     },
-    
+
     /**
      * Set the callback to be executed when the operation completes.
      * @method withCallback
@@ -340,8 +339,8 @@ Builder.prototype = {
     /**
      * Provide a conflict resolver to resolve siblings.
      * If siblings are present Riak will return all of them. The provided
-     * function will be used to resolve these to a single response. 
-     * 
+     * function will be used to resolve these to a single response.
+     *
      * If a conflict resolver is not provided all siblings will be returned.
      * @method withConflictResolver
      * @param {Function} conflictResolver - the conflict resolver to be used.
@@ -354,8 +353,8 @@ Builder.prototype = {
     /**
      * Convert the value stored in Riak to a JS object.
      * Values are stored in Riak as bytes. Setting this to true will
-     * convert the value to a JS object using JSON.parse() before 
-     * passing them to the conflict resolver. 
+     * convert the value to a JS object using JSON.parse() before
+     * passing them to the conflict resolver.
      * @method withConvertValueToJs
      * @param {Boolean} convert - true to convert the value(s), false otherwise.
      * @chainable
@@ -370,10 +369,13 @@ Builder.prototype = {
      * @return {FetchValue}
      */
     build : function() {
-        return new FetchValue(this, this.callback);
+        var cb = this.callback;
+        delete this.callback;
+        return new FetchValue(this, cb);
     }
-        
+
 };
 
 module.exports = FetchValue;
 module.exports.Builder = Builder;
+
diff --git a/lib/commands/kv/listbuckets.js b/lib/commands/kv/listbuckets.js
index 9e5760b..6da8caa 100644
--- a/lib/commands/kv/listbuckets.js
+++ b/lib/commands/kv/listbuckets.js
@@ -27,14 +27,14 @@ var Joi = require('joi');
 
 /**
  * Command used to list buckets in a bucket type.
- * 
+ *
  * As a convenience, a builder class is provided;
- * 
+ *
  *     var listBuckets = new ListBuckets.Builder()
  *                  .withBucketType('myBucketType')
  *                  .withCallback(myCallback)
  *                  .build();
- * 
+ *
  * See {{#crossLink "ListBuckets.Builder"}}ListBuckets.Builder{{/crossLink}}
  * @class ListBuckets
  * @constructor
@@ -52,48 +52,48 @@ var Joi = require('joi');
  */
 function ListBuckets(options, callback) {
     CommandBase.call(this, 'RpbListBucketsReq', 'RpbListBucketsResp', callback);
-    
+
     var self = this;
     Joi.validate(options, schema, function(err, options) {
-       
+
         if (err) {
             throw err;
         }
-    
+
         self.options = options;
     });
-    
+
     if (!this.options.stream) {
         this.buckets = [];
     }
-    
+
     this.remainingTries = 1;
 }
 
 inherits(ListBuckets, CommandBase);
 
 ListBuckets.prototype.constructPbRequest = function() {
-  
+
     var protobuf = this.getPbReqBuilder();
-    
+
     protobuf.setType(new Buffer(this.options.bucketType));
     protobuf.setTimeout(this.options.timeout);
     // We always stream from Riak 'cause it's better
     protobuf.stream = true;
-    
+
     return protobuf;
-    
+
 };
 
 ListBuckets.prototype.onSuccess = function(rpbListBucketsResp) {
-    
+
     var bucketsToSend = new Array(rpbListBucketsResp.buckets.length);
     if (rpbListBucketsResp.buckets.length) {
             for (var i = 0; i < rpbListBucketsResp.buckets.length; i++) {
             bucketsToSend[i] = rpbListBucketsResp.buckets[i].toString('utf8');
         }
     }
-        
+
     if (this.options.stream) {
         this._callback(null, { buckets: bucketsToSend, done: rpbListBucketsResp.done });
     } else {
@@ -102,36 +102,35 @@ ListBuckets.prototype.onSuccess = function(rpbListBucketsResp) {
             this._callback(null, { buckets: this.buckets, done: rpbListBucketsResp.done});
         }
     }
-    
+
     return rpbListBucketsResp.done;
-    
+
 };
 
 var schema = Joi.object().keys({
    bucketType: Joi.string().default('default'),
-   callback : Joi.func().strip().optional(),
    stream : Joi.boolean().default(true),
    timeout: Joi.number().default(null)
 });
 
 /**
  * A builder for constructing ListBuckets instances.
- * 
+ *
  * Rather than having to manually construct the __options__ and instantiating
  * a ListBuckets directly, this builder may be used.
- * 
+ *
  *     var listBuckets = new ListBuckets.Builder()
  *                        .withBucketType('myBucketType')
  *                        .withCallback(myCallback)
  *                        .build();
- *       
+ *
  * @class ListBuckets.Builder
  * @constructor
  */
 function Builder(){}
 
 Builder.prototype = {
-    
+
     /**
      * Set the bucket type.
      * If not supplied, 'default' is used.
@@ -146,11 +145,11 @@ Builder.prototype = {
     /**
      * Stream the results.
      * Setting this to true will cause you callback to be called as the results
-     * are returned from Riak. Set to false the result set will be buffered and 
-     * delevered via a single call to your callback. Note that on large result sets 
+     * are returned from Riak. Set to false the result set will be buffered and
+     * delevered via a single call to your callback. Note that on large result sets
      * this is very memory intensive.
      * @method withStreaming
-     * @param {Boolean} [stream=true] Set whether or not to stream the results 
+     * @param {Boolean} [stream=true] Set whether or not to stream the results
      * @chainable
      */
     withStreaming : function(stream) {
@@ -184,10 +183,12 @@ Builder.prototype = {
     /**
      * Construct a ListBuckets instance.
      * @method build
-     * @return {ListBuckets} 
+     * @return {ListBuckets}
      */
     build : function() {
-        return new ListBuckets(this, this.callback);
+        var cb = this.callback;
+        delete this.callback;
+        return new ListBuckets(this, cb);
     }
 };
 
diff --git a/lib/commands/kv/listkeys.js b/lib/commands/kv/listkeys.js
index 7489986..7f17a1e 100644
--- a/lib/commands/kv/listkeys.js
+++ b/lib/commands/kv/listkeys.js
@@ -24,17 +24,17 @@ var Joi = require('joi');
 
 /**
  * Command used to list keys in a bucket.
- * 
+ *
  * Note that this is a __very__ expensive operation and not recommended for production use.
- * 
+ *
  * As a convenience, a builder class is provided;
- * 
+ *
  *     var listKeys = new ListKeys.Builder()
  *                  .withBucketType('myBucketType')
  *                  .withBucket('myBucket')
  *                  .withCallback(myCallback)
  *                  .build();
- * 
+ *
  * See {{#crossLink "ListKeys.Builder"}}ListKeys.Builder{{/crossLink}}
  * @class ListKeys
  * @constructor
@@ -54,91 +54,90 @@ var Joi = require('joi');
  */
 function ListKeys(options, callback) {
     CommandBase.call(this, 'RpbListKeysReq', 'RpbListKeysResp', callback);
-    
+
     var self = this;
     Joi.validate(options, schema, function(err, options) {
-       
+
         if (err) {
             throw err;
         }
-    
+
         self.options = options;
     });
-    
+
     if (!this.options.stream) {
         this.keys = [];
     }
-    
+
     this.remainingTries = 1;
 }
 
 inherits(ListKeys, CommandBase);
 
 ListKeys.prototype.constructPbRequest = function() {
-  
+
     var protobuf = this.getPbReqBuilder();
-    
+
     protobuf.setBucket(new Buffer(this.options.bucket));
     protobuf.setType(new Buffer(this.options.bucketType));
     protobuf.setTimeout(this.options.timeout);
-    
+
     return protobuf;
-    
+
 };
 
 ListKeys.prototype.onSuccess = function(rpbListKeysResp) {
-    
+
     var keysToSend = new Array(rpbListKeysResp.keys.length);
     if (rpbListKeysResp.keys.length) {
         for (var i = 0; i < rpbListKeysResp.keys.length; i++) {
             keysToSend[i] = rpbListKeysResp.keys[i].toString('utf8');
         }
     }
-        
+
     if (this.options.stream) {
-        this._callback(null, { bucketType: this.options.bucketType, 
-            bucket: this.options.bucket, 
+        this._callback(null, { bucketType: this.options.bucketType,
+            bucket: this.options.bucket,
             keys: keysToSend, done: rpbListKeysResp.done});
     } else {
         Array.prototype.push.apply(this.keys, keysToSend);
         if (rpbListKeysResp.done) {
-            this._callback(null, {  bucketType: this.options.bucketType, 
-                bucket: this.options.bucket, keys: this.keys, 
+            this._callback(null, {  bucketType: this.options.bucketType,
+                bucket: this.options.bucket, keys: this.keys,
                 done: rpbListKeysResp.done });
         }
     }
-    
+
     return rpbListKeysResp.done;
-    
+
 };
 
 var schema = Joi.object().keys({
    bucket: Joi.string().required(),
    bucketType: Joi.string().default('default'),
-   callback : Joi.func().strip().optional(),
    stream : Joi.boolean().default(true),
    timeout: Joi.number().default(null)
 });
 
 /**
  * A builder for constructing ListKeys instances.
- * 
+ *
  * Rather than having to manually construct the __options__ and instantiating
  * a ListKeys directly, this builder may be used.
- * 
+ *
  *     var listKeys = new ListKeys.Builder()
  *                  .withBucketType('myBucketType')
  *                  .withBucket('myBucket')
  *                  .withCallback(myCallback)
  *                  .build();
- *       
+ *
  * @class ListKeys.Builder
  * @constructor
  */
 function Builder() {}
 
 Builder.prototype = {
-  
+
     /**
      * Set the bucket.
      * @method withBucket
@@ -163,11 +162,11 @@ Builder.prototype = {
     /**
      * Stream the results.
      * Setting this to true will cause you callback to be called as the results
-     * are returned from Riak. Set to false the result set will be buffered and 
-     * delevered via a single call to your callback. Note that on large result sets 
+     * are returned from Riak. Set to false the result set will be buffered and
+     * delevered via a single call to your callback. Note that on large result sets
      * this is very memory intensive.
      * @method withStreaming
-     * @param {Boolean} [stream=true] Set whether or not to stream the results 
+     * @param {Boolean} [stream=true] Set whether or not to stream the results
      * @chainable
      */
     withStreaming : function(stream) {
@@ -203,12 +202,14 @@ Builder.prototype = {
     /**
      * Construct a ListKeys instance.
      * @method build
-     * @return {ListKeys} 
+     * @return {ListKeys}
      */
     build : function() {
-        return new ListKeys(this, this.callback);
+        var cb = this.callback;
+        delete this.callback;
+        return new ListKeys(this, cb);
     }
-    
+
 };
 
 module.exports = ListKeys;
diff --git a/lib/commands/kv/secondaryindexquery.js b/lib/commands/kv/secondaryindexquery.js
index 5e6dc18..e2e5fa8 100644
--- a/lib/commands/kv/secondaryindexquery.js
+++ b/lib/commands/kv/secondaryindexquery.js
@@ -29,21 +29,21 @@ var RiakObject = require('./riakobject');
 
 
 /**
- * Command used to perform a secondary index query. 
- * 
+ * Command used to perform a secondary index query.
+ *
  * As a convenience, a builder class is provided:
- * 
+ *
  *     var query = new SecondaryIndexQuery.Builder()
  *                  .withBucket('myBucket')
  *                  .withIndexName('email_bin')
  *                  .withIndexKey('roach@basho.com')
  *                  .withCallback(myCallback)
  *                  .build();
- *                  
+ *
  * See {{#crossLink "SecondaryIndexQuery.Builder"}}SecondaryIndexQuery.Builder{{/crossLink}}
- *                  
+ *
  * @class SecondaryIndexQuery
- * @constructor   
+ * @constructor
  * @param {Object} options The options for this command.
  * @param {String} [options.bucketType=default] The bucket type in riak. If not supplied 'default' is used.
  * @param {String} options.bucket The bucket in riak.
@@ -67,27 +67,25 @@ var RiakObject = require('./riakobject');
  */
 function SecondaryIndexQuery(options, callback) {
     CommandBase.call(this, 'RpbIndexReq', 'RpbIndexResp', callback);
-    
+
     var self = this;
     Joi.validate(options, schema, function(err, options) {
-       
+
         if (err) {
             throw err;
         }
-    
+
         // I tried making this work in the Joi schema and finally gave up. It seems
         // alternatives can't work with multiple conditionals.
         if (options.indexKey === null && (options.rangeStart === null || options.rangeEnd === null) ) {
-            throw ('either \'indxKey\' or \'rangeStart\' + \'rangeEnd\' are required');
-        } 
-    
+            throw ('either \'indexKey\' or \'rangeStart\' + \'rangeEnd\' are required');
+        }
+
         self.options = options;
     });
-    
-    
-    
+
     this.remainingTries = 1;
-    
+
     if (!this.options.stream) {
         this.responses = [];
     }
@@ -96,16 +94,16 @@ function SecondaryIndexQuery(options, callback) {
 inherits(SecondaryIndexQuery, CommandBase);
 
 SecondaryIndexQuery.prototype.constructPbRequest = function() {
-  
+
     var protobuf = this.getPbReqBuilder();
-    // We always stream from Riak. 
+    // We always stream from Riak.
     protobuf.setStream(true);
-    
+
     protobuf.setBucket(new Buffer(this.options.bucket));
     protobuf.setType(new Buffer(this.options.bucketType));
     protobuf.setIndex(new Buffer(this.options.indexName));
     protobuf.setReturnTerms(this.options.returnKeyAndIndex);
-    
+
     if (this.options.indexKey !== null) {
         // _int index requests take ... strings, not numbers
         protobuf.setKey(new Buffer(this.options.indexKey.toString()));
@@ -115,31 +113,31 @@ SecondaryIndexQuery.prototype.constructPbRequest = function() {
         protobuf.setRangeMax(new Buffer(this.options.rangeEnd.toString()));
         protobuf.setQtype(RpbIndexReq.IndexQueryType.range);
     }
-    
+
     if (!this.options.maxResults && this.options.paginationSort) {
         protobuf.setPaginationSort(this.options.paginationSort);
     }
     protobuf.setMaxResults(this.options.maxResults);
     protobuf.setContinuation(this.options.continuation);
     protobuf.setTimeout(this.options.timeout);
-    
+
     return protobuf;
 };
 
 SecondaryIndexQuery.prototype.onSuccess = function(rpbIndexResp) {
-    
+
     /*
-    * @private 
-    * The 2i API is inconsistent on the Riak side. If it's not 
-    * a range query, return_terms is ignored it only returns the 
+    * @private
+    * The 2i API is inconsistent on the Riak side. If it's not
+    * a range query, return_terms is ignored it only returns the
     * list of object keys and you have to have
     * preserved the index key if you want to return it to the user
-    * with the results. 
-    * 
+    * with the results.
+    *
     * Also, the $key index queries just ignore return_terms altogether.
     */
-   
-   
+
+
     var i, resultsToReturn;
     if (rpbIndexResp.results.length) {
         // Index keys and object keys were returned
@@ -164,10 +162,10 @@ SecondaryIndexQuery.prototype.onSuccess = function(rpbIndexResp) {
             resultsToReturn[i] = { indexKey: key, objectKey: rpbIndexResp.keys[i].toString('utf8') };
         }
     }
-    
-    
+
+
     var continuation = rpbIndexResp.continuation;
-    
+
     if (this.options.stream) {
         this._callback(null, { values: resultsToReturn, done: rpbIndexResp.done, continuation: continuation });
     } else {
@@ -176,9 +174,9 @@ SecondaryIndexQuery.prototype.onSuccess = function(rpbIndexResp) {
             this._callback(null, { values: this.responses, done : true, continuation: continuation });
         }
     }
-    
+
     return rpbIndexResp.done;
-    
+
 };
 
 // Explicitly set null on options for protobufs and for conditionals
@@ -192,7 +190,6 @@ var schema = Joi.object().keys({
    returnKeyAndIndex: Joi.boolean().default(null).optional(),
    maxResults: Joi.number().default(null).optional(),
    continuation: Joi.any().default(null).optional(),
-   callback: Joi.func().strip().optional(),
    timeout: Joi.number().default(null).optional(),
    stream: Joi.boolean().default(true).optional(),
    paginationSort: Joi.boolean().default(null).optional()
@@ -201,24 +198,24 @@ var schema = Joi.object().keys({
 
 /**
  * A builder for constructing SecondaryIndexquery instances.
- * 
+ *
  * Rather than having to manually construct the __options__ and instantiating
  * a SecondaryIndexQuery directly, this builder may be used.
- * 
+ *
  *     var query = new SecondaryIndexQuery.Builder()
  *                  .withBucket('myBucket')
  *                  .withIndexName('email_bin')
  *                  .withIndexKey('roach@basho.com')
  *                  .withCallback(myCallback)
  *                  .build();
- *       
+ *
  * @class SecondaryIndexQuery.Builder
  * @constructor
  */
 function Builder() {}
 
 Builder.prototype = {
-    
+
     /**
      * Set the bucket.
      * @method withBucket
@@ -252,7 +249,7 @@ Builder.prototype = {
     },
     /**
      * Set a single secondary index key to use for query.
-     * Note that you can only set a single key, or a range. 
+     * Note that you can only set a single key, or a range.
      * @method withIndexKey
      * @param {String|Number} indexKey the secondary index key.
      * @chainable
@@ -287,13 +284,13 @@ Builder.prototype = {
     },
     /**
      * Set the maximum number of results returned by the query.
-     * 
-     * When asking for large result sets, it is often desirable to ask the 
-     * servers to return chunks of results instead of a firehose. 
-     * You can do so using this method, where maxResults is the number of 
+     *
+     * When asking for large result sets, it is often desirable to ask the
+     * servers to return chunks of results instead of a firehose.
+     * You can do so using this method, where maxResults is the number of
      * results you'd like to receive.
-     * 
-     * Assuming more keys are available, a continuation value will be included 
+     *
+     * Assuming more keys are available, a continuation value will be included
      * in the results to allow the client to request the next page.
      * @method withMaxResults
      * @param {Number} maxResults the max number of results to return.
@@ -343,11 +340,11 @@ Builder.prototype = {
     /**
      * Stream the results.
      * Setting this to true will cause you callback to be called as the results
-     * are returned from Riak. Set to false the result set will be buffered and 
-     * delevered via a single call to your callback. Note that on large result sets 
+     * are returned from Riak. Set to false the result set will be buffered and
+     * delevered via a single call to your callback. Note that on large result sets
      * this is very memory intensive.
      * @method withStreaming
-     * @param {Boolean} [stream=true] Set whether or not to stream the results 
+     * @param {Boolean} [stream=true] Set whether or not to stream the results
      * @chainable
      */
     withStreaming : function(stream) {
@@ -356,7 +353,7 @@ Builder.prototype = {
     },
     /**
      * Set whether to sort the results of a non-paginated 2i query.
-     * If you are not using pagination (setting withMaxResults()) the 
+     * If you are not using pagination (setting withMaxResults()) the
      * default behavior in Riak is to not sort the result set.
      * Setting this to true will sort the results before returning them.
      * __Note that this is not recommended for queries that could return a large
@@ -375,10 +372,13 @@ Builder.prototype = {
      * @return {SecondaryIndexQuery}
      */
     build : function() {
-        return new SecondaryIndexQuery(this, this.callback);
+        var cb = this.callback;
+        delete this.callback;
+        return new SecondaryIndexQuery(this, cb);
     }
-    
+
 };
 
 module.exports = SecondaryIndexQuery;
 module.exports.Builder = Builder;
+
diff --git a/lib/commands/kv/storebucketprops.js b/lib/commands/kv/storebucketprops.js
index 2943de0..2d19aba 100644
--- a/lib/commands/kv/storebucketprops.js
+++ b/lib/commands/kv/storebucketprops.js
@@ -29,15 +29,15 @@ var Joi = require('joi');
 
 /**
  * Command used to set the properties on a bucket in Riak.
- * 
+ *
  * As a convenience, a builder class is provided:
- * 
+ *
  *     var storeProps = new StoreBucketProps.Builder()
  *                  .withAllowMult(true)
  *                  .build();
- *                  
+ *
  * See {{#crossLink "StoreBucketProps.Builder"}}StoreBucketProps.Builder{{/crossLink}}
- * 
+ *
  * @class StoreBucketProps
  * @constructor
  * @param {Object} options The properties to store
@@ -66,22 +66,22 @@ var Joi = require('joi');
  * @param {Object[]} [options.postcommit] Array of postcommit hooks
  * @param {Function} callback The callback to be executed when the operation completes.
  * @param {String} callback.err An error message. Will be null if no error.
- * @param {Boolean} callback.response the response from Riak. This will be true. 
+ * @param {Boolean} callback.response the response from Riak. This will be true.
  * @extends CommandBase
  */
 function StoreBucketProps(options, callback) {
     CommandBase.call(this, 'RpbSetBucketReq', 'RpbSetBucketResp', callback);
-    
+
     var self = this;
     Joi.validate(options, schema, function(err, options) {
-       
+
         if (err) {
             throw err;
         }
-    
+
         self.options = options;
     });
-    
+
     this.remainingTries = 1;
 
 }
@@ -89,14 +89,14 @@ function StoreBucketProps(options, callback) {
 inherits(StoreBucketProps, CommandBase);
 
 StoreBucketProps.prototype.constructPbRequest = function() {
-    
+
     var protobuf = this.getPbReqBuilder();
-    
+
     protobuf.setBucket(new Buffer(this.options.bucket));
     protobuf.setType(new Buffer(this.options.bucketType));
-    
+
     var props = new RpbBucketProps();
-    
+
     props.setNVal(this.options.nVal > 0 ? this.options.nVal : null );
     props.setOldVclock(this.options.oldVClock >= 0 ? this.options.oldVClock : null);
     props.setYoungVclock(this.options.youngVClock >= 0 ? this.options.youngVClock : null);
@@ -108,36 +108,36 @@ StoreBucketProps.prototype.constructPbRequest = function() {
     props.setPw(this.options.pw >= 0 ? this.options.pw : null);
     props.setDw(this.options.dw >= 0 ? this.options.dw : null);
     props.setRw(this.options.rw >= 0 ? this.options.rw : null);
-    
-    
+
+
     props.setBasicQuorum(typeof this.options.basicQuorum === 'boolean' ? this.options.basicQuorum : null);
     props.setNotfoundOk(typeof this.options.notFoundOk === 'boolean' ? this.options.notFoundOk : null);
     props.setSearch(typeof this.options.search === 'boolean' ? this.options.search : null);
     props.setAllowMult(typeof this.options.allowMult === 'boolean' ? this.options.allowMult : null);
     props.setLastWriteWins(typeof this.options.lastWriteWins === 'boolean' ? this.options.lastWriteWins : null);
-    
+
     props.setBackend(this.options.backend ? new Buffer(this.options.backend) : null);
     props.setSearchIndex(this.options.searchIndex ? new Buffer(this.options.searchIndex) : null);
-    
+
     if (this.options.precommit) {
         props.setPrecommit(this._convertHooks(this.options.precommit));
     }
-    
+
     if (this.options.postcommit) {
         props.setPostcommit(this._convertHooks(this.options.postcommit));
     }
-    
+
     if (this.options.chashKeyfun) {
         var modfun = new RpbModFun();
         modfun.module = new Buffer(this.options.chashKeyfun.mod);
         modfun.function = new Buffer(this.options.chashKeyfun.fun);
         props.setChashKeyfun(modfun);
     }
-    
+
     protobuf.setProps(props);
-    
+
     return protobuf;
-    
+
 };
 
 StoreBucketProps.prototype._convertHooks = function(hooks) {
@@ -158,12 +158,12 @@ StoreBucketProps.prototype._convertHooks = function(hooks) {
 };
 
 StoreBucketProps.prototype.onSuccess = function(rpbSetBucketResp) {
-    
+
     // There is not response from riak except a code. rpbSetBucketResp
     // will be null upon success.
     this._callback(null, true);
     return true;
-    
+
 };
 
 var schema = Joi.object().keys({
@@ -175,7 +175,6 @@ var schema = Joi.object().keys({
     dw: Joi.number().optional(),
     pw: Joi.number().optional(),
     rw: Joi.number().optional(),
-    callback: Joi.func().strip().optional(),
     notFoundOk: Joi.boolean().optional(),
     nVal: Joi.number().optional(),
     allowMult: Joi.boolean().optional(),
@@ -191,25 +190,25 @@ var schema = Joi.object().keys({
     search : Joi.boolean().optional(),
     searchIndex : Joi.string().optional(),
     chashKeyfun : Joi.object().optional()
-    
+
 });
 
 
 /**
  * A builder for constructing StoreBucketProps instances
- * 
+ *
  * Rather than having to manually construct the __options__ and instantiating
  * a StoreBucketProps directly, this builder may be used.
  *
  *     var storeProps = new StoreBucketProps.Builder()
  *                  .withAllowMult(true)
  *                  .build();
- *                  
+ *
  * @class StoreBucketProps.Builder
- * @constructor 
+ * @constructor
  */
 function Builder() {
-    
+
     this.precommit = [];
     this.postcommit = [];
 }
@@ -269,8 +268,8 @@ Builder.prototype = {
         return this;
     },
     /**
-    * Add a pre-commit hook. 
-    * 
+    * Add a pre-commit hook.
+    *
     * @method addPrecommitHook
     * @param {Object} precommitHook the hook to add.
     * @chainable
@@ -280,8 +279,8 @@ Builder.prototype = {
         return this;
     },
     /**
-    * Add a pre-commit hook. 
-    * 
+    * Add a pre-commit hook.
+    *
     * @method addPostcommitHook
     * @param {Object} postcommitHook the hook to add.
     * @chainable
@@ -331,13 +330,13 @@ Builder.prototype = {
         return this;
     },
     /**
-    * Set the backend used by this bucket. 
+    * Set the backend used by this bucket.
     * Only applies when using
     * riak_kv_multi_backend in Riak.
     * @method withBackend
     * @param {Sring} backend the name of the backend to use.
     * @chainable
-    */ 
+    */
     withBackend : function(backend) {
         this.backend = backend;
         return this;
@@ -414,7 +413,7 @@ Builder.prototype = {
     /**
     * Set the basic_quorum value.
     * The parameter controls whether a read request should return early in
-    * some fail cases. 
+    * some fail cases.
     * E.g. If a quorum of nodes has already
     * returned notfound/error, don't wait around for the rest.
     * @method withBasicQuorum
@@ -452,7 +451,7 @@ Builder.prototype = {
         return this;
     },
     /**
-    * Associate a Search Index. 
+    * Associate a Search Index.
     * This only applies if Yokozuna is enabled in
     * Riak v2.0.
     * @method withSearchIndex
@@ -465,7 +464,7 @@ Builder.prototype = {
     },
     /**
      * Set the chash_keyfun value.
-     * 
+     *
      * @method withChashkeyFunction
      * @param {Object} func a object representing the Erlang func to use.
      * @chainable
@@ -479,7 +478,7 @@ Builder.prototype = {
      * @method withCallback
      * @param {Function} callback The callback to be executed when the operation completes.
      * @param {String} callback.err An error message. Will be null if no error.
-     * @param {Boolean} callback.response the response from Riak. This will be true. 
+     * @param {Boolean} callback.response the response from Riak. This will be true.
      * @chainable
      */
     withCallback : function(callback) {
@@ -492,9 +491,11 @@ Builder.prototype = {
      * @return {StoreBucketProps}
      */
     build : function() {
-        return new StoreBucketProps(this, this.callback);
+        var cb = this.callback;
+        delete this.callback;
+        return new StoreBucketProps(this, cb);
     }
-    
+
 };
 
 module.exports = StoreBucketProps;
diff --git a/lib/commands/kv/storevalue.js b/lib/commands/kv/storevalue.js
index 2d79fc5..f15ae2b 100644
--- a/lib/commands/kv/storevalue.js
+++ b/lib/commands/kv/storevalue.js
@@ -27,17 +27,17 @@ var Joi = require('joi');
 
 /**
  * Command used to store data in Riak.
- * 
+ *
  * As a convenience, a builder class is provided:
- * 
+ *
  *      var storeValue = new StoreValue.Builder()
  *          .withBucket('myBucket')
  *          .withKey('myKey')
  *          .withContent(myObj);
  *          .build();
- *          
+ *
  * See {{#crossLink "StoreValue.Builder"}}StoreValue.Builder{{/crossLink}}
- * 
+ *
  * @class StoreValue
  * @constructor
  * @param {Object} options The options for this command.
@@ -69,33 +69,33 @@ function StoreValue(options, callback) {
     CommandBase.call(this, 'RpbPutReq', 'RpbPutResp', callback);
     var self = this;
     Joi.validate(options, schema, function(err, options) {
-       
+
         if (err) {
             throw err;
         }
-    
+
         self.options = options;
-        
+
         if (!options.bucket && ((options.value instanceof RiakObject) && !options.value.bucket)) {
             throw 'Must supply bucket directly or via a RiakObject';
         }
-        
+
     });
-    
+
     this.remainingTries = 1;
 }
 
 inherits(StoreValue, CommandBase);
 
 StoreValue.prototype.constructPbRequest = function() {
-    
+
     var protobuf = this.getPbReqBuilder();
-    
-    // RiakObject values take precidence 
+
+    // RiakObject values take precidence
     var value = this.options.value;
-    
+
     if (value instanceof RiakObject) {
-    
+
         if (value.hasOwnProperty('vclock')) {
             this.options.vclock = value.vclock;
         }
@@ -111,7 +111,7 @@ StoreValue.prototype.constructPbRequest = function() {
     } else {
         value = new RiakObject().setValue(this.options.value);
     }
-    
+
     protobuf.setBucket(new Buffer(this.options.bucket));
     protobuf.setType(new Buffer(this.options.bucketType));
     if (this.options.key) {
@@ -126,29 +126,29 @@ StoreValue.prototype.constructPbRequest = function() {
     protobuf.setTimeout(this.options.timeout);
     protobuf.setIfNotModified(this.options.ifNotModified);
     protobuf.setIfNoneMatch(this.options.ifNoneMatch);
-    
-    
-    
+
+
+
     var rpbContent = RiakObject.populateRpbContentFromRiakObject(value);
-    
+
     protobuf.setContent(rpbContent);
-    
+
     return protobuf;
-    
+
 };
 
 StoreValue.prototype.onSuccess = function(rpbPutResp) {
-    
+
     // unless returnHead or returnMeta were specified, or if no key was supplied
-    // Riak doesn't return any data 
+    // Riak doesn't return any data
     var response = {};
     if (rpbPutResp) {
-                
+
         var responseKey = null;
 
         if (rpbPutResp.getKey()) {
             responseKey = rpbPutResp.getKey().toString('utf8');
-        } 
+        }
 
         var values;
         var vclock = null;
@@ -163,14 +163,14 @@ StoreValue.prototype.onSuccess = function(rpbPutResp) {
                 riakObject.bucket = this.options.bucket;
                 riakObject.bucketType = this.options.bucketType;
                 riakObject.key = responseKey ? responseKey : this.options.key;
-                
+
                 values[i] = riakObject;
             }
-            
+
             if (this.options.conflictResolver) {
                 values = [this.options.conflictResolver(values)];
             }
-            
+
         } else {
             values =[];
         }
@@ -180,17 +180,16 @@ StoreValue.prototype.onSuccess = function(rpbPutResp) {
     } else {
         response = { generatedKey: null, vclock: null, values: [] };
     }
-    
+
     this._callback(null, response);
-    
-    return true;    
+
+    return true;
 };
 
 var schema = Joi.object().keys({
     bucket: Joi.string().optional(),
     bucketType: Joi.string().default('default'),
     key: Joi.string().default(null).optional(),
-    callback: Joi.func().strip().optional(),
     value: Joi.any().required(),
     w: Joi.number().default(null).optional(),
     dw: Joi.number().default(null).optional(),
@@ -208,23 +207,23 @@ var schema = Joi.object().keys({
 
 /**
  * A builder for constructing StoreValue instances.
- * 
+ *
  * Rather than having to manually construct the __options__ and instantiating
  * a StoreValue directly, this builder may be used.
- * 
+ *
  *     var storeValue = new StoreValue.Builder()
  *          .withBucket('myBucket')
  *          .withKey('myKey')
  *          .withContent(myObj);
  *          .build();
- *       
+ *
  * @class StoreValue.Builder
  * @constructor
  */
 function Builder() {}
 
 Builder.prototype = {
-    
+
     /**
      * Set the bucket.
      * Note that this can also be provided via RiakObject passed in via withContent() and
@@ -277,7 +276,7 @@ Builder.prototype = {
     },
     /**
      * Set the vector clock.
-     * Convenience method if a RiakObject is not supplied as content. 
+     * Convenience method if a RiakObject is not supplied as content.
      * Note that a vclock supplied via RiakObject in withContent() will have precendence over this.
      * @method withVClock
      * @param {Buffer} vclock a vector clock returned from a previous fetch
@@ -324,10 +323,10 @@ Builder.prototype = {
     },
     /**
     * Return the object after storing (including any siblings).
-    * If siblings are present, an optional conflictResolver can be 
+    * If siblings are present, an optional conflictResolver can be
     * provided to resolve them.
     * @method withReturnBody
-    * @param {boolean} returnBody true to return the object. 
+    * @param {boolean} returnBody true to return the object.
     * @param {boolean} [convertToJs] convert the returned value(s) to JS objects using JSON.parse()
     * @param {Function} [conflictResolver] the conflict resolver
     * @param {RiakObject[]} conflictResolver.riakobjects array of RiakObjects returned by Riak.
@@ -343,19 +342,19 @@ Builder.prototype = {
                 this.conflictResolver = arg;
             }
         }
-        
+
         return this;
     },
     /**
     * Return the metadata after storing the value.
-    * 
-    * Causes Riak to only return the metadata for the object. 
-    * If siblings are present, an optional conflictResolver can be 
+    *
+    * Causes Riak to only return the metadata for the object.
+    * If siblings are present, an optional conflictResolver can be
     * provided to resolve them.
     * @method withReturnHead
     * @param {Function} [conflictResolver] the conflict resolver
     * @param {RiakObject[]} conflictResolver.riakobjects array of RiakObjects returned by Riak.
-    * @param {boolean} returnHead true to return only metadata. 
+    * @param {boolean} returnHead true to return only metadata.
     * @chainable
     */
     withReturnHead : function(returnHead, conflictResolver) {
@@ -366,7 +365,7 @@ Builder.prototype = {
     /**
     * Set the if_not_modified flag.
     *
-    * Setting this to true means to store the value only if the 
+    * Setting this to true means to store the value only if the
     * supplied vclock matches the one in the database.
     *
     * Be aware there are several cases where this may not actually happen.
@@ -381,11 +380,11 @@ Builder.prototype = {
     },
     /**
     * Set the if_none_match flag.
-    * 
-    * Setting this to true means store the value only if this 
-    * bucket/key combination are not already defined. 
-    * 
-    * Be aware that there are several cases where 
+    *
+    * Setting this to true means store the value only if this
+    * bucket/key combination are not already defined.
+    *
+    * Be aware that there are several cases where
     * this may not actually happen. Use of this option is discouraged.
     * @method withIfNoneMatch
     * @param {boolean} ifNoneMatch the if_non-match value.
@@ -426,11 +425,12 @@ Builder.prototype = {
      * @return {StoreValue} a StoreValue instance
      */
     build : function() {
-        return new StoreValue(this, this.callback);
+        var cb = this.callback;
+        delete this.callback;
+        return new StoreValue(this, cb);
     }
-    
-};
 
+};
 
 module.exports = StoreValue;
 module.exports.Builder = Builder;
diff --git a/lib/commands/mapreduce/mapreduce.js b/lib/commands/mapreduce/mapreduce.js
index cb19cd1..40e72e4 100644
--- a/lib/commands/mapreduce/mapreduce.js
+++ b/lib/commands/mapreduce/mapreduce.js
@@ -27,11 +27,11 @@ var Joi = require('joi');
 
 /**
  * Command used to perform a Map-Reduce query in Riak.
- * 
- * The Riak Map-Reduce API uses JSON for its query. 
- * 
+ *
+ * The Riak Map-Reduce API uses JSON for its query.
+ *
  * A typical map-reduce query (JSON) will look like:
- * 
+ *
  *     {
  *       "inputs": "goog",
  *       "query": [
@@ -50,36 +50,36 @@ var Joi = require('joi');
  *         }
  *       ]
  *     }
- * 
+ *
  * For more info see:
  * [Loading Data and Running MapReduce](http://docs.basho.com/riak/latest/tutorials/fast-track/Loading-Data-and-Running-MapReduce-Queries/)
- * 
+ *
  * @class MapReduce
  * @constructor
  * @param {String} query The Map-Reduce query. This is a string containing JSON.
- * @param {Function} callback The callback to be executed by this command. 
+ * @param {Function} callback The callback to be executed by this command.
  * @param {String} callback.err An error message. Will be null if no error.
- * @param {Object} callback.response the response from Riak. 
+ * @param {Object} callback.response the response from Riak.
  * @param {Boolean} callback.response.done True if the entire response has been received.
  * @param {Number} callback.response.phase The phase the response is from.
- * @param {Object[]} callback.response.response The results. 
+ * @param {Object[]} callback.response.response The results.
  * @param {Boolean} [stream=true] stream the results or accumulate before calling callback.
  * @extends CommandBase
  */
 function MapReduce(query, callback, stream) {
     CommandBase.call(this, 'RpbMapRedReq', 'RpbMapRedResp', callback);
-    
+
     var self = this;
-    Joi.validate({ query: query, stream: stream}, schema, function(err, options) {
-       
+    Joi.validate({ query: query, stream: stream }, schema, function(err, options) {
+
         if (err) {
             throw err;
         }
-    
+
         self.query = options.query;
         self.stream = options.stream;
     });
-    
+
     this.remainingTries = 1;
     if (!this.stream) {
         this.response = {};
@@ -89,19 +89,19 @@ function MapReduce(query, callback, stream) {
 inherits(MapReduce, CommandBase);
 
 MapReduce.prototype.constructPbRequest = function() {
-  
+
     var protobuf = this.getPbReqBuilder();
-    
+
     protobuf.setContentType(new Buffer('application/json'));
     protobuf.setRequest(new Buffer(this.query));
-    
+
     return protobuf;
-    
+
 };
 
 MapReduce.prototype.onSuccess = function(rpbMapRedResp) {
-    
-    
+
+
      var done = rpbMapRedResp.done ? true : false;
     // The last message is usually empty with only 'done' when streaming
     var responseArray = null;
@@ -109,16 +109,16 @@ MapReduce.prototype.onSuccess = function(rpbMapRedResp) {
     if (rpbMapRedResp.getResponse()) {
         responseArray = JSON.parse(rpbMapRedResp.getResponse().toString('utf8'));
         phase = rpbMapRedResp.phase ? rpbMapRedResp.phase : 0;
-    
+
         if (!this.stream) {
             if (!this.response['phase_' + phase]) {
                 this.response['phase_' + phase] = responseArray;
             } else {
                 Array.prototype.push.apply(this.response['phase_' + phase], responseArray);
             }
-        } 
+        }
     }
-    
+
     if (!this.stream) {
         if (done) {
             this.response.done = true;
@@ -127,15 +127,15 @@ MapReduce.prototype.onSuccess = function(rpbMapRedResp) {
     } else {
         this._callback(null, { phase : phase, response: responseArray, done: done});
     }
-    
+
     return done;
-    
+
 };
 
 var schema = Joi.object().keys({
     query: Joi.string().required(),
-    callback: Joi.func().strip().optional(),
     stream: Joi.boolean().default(true).optional()
 });
 
 module.exports = MapReduce;
+
diff --git a/lib/commands/yokozuna/deleteindex.js b/lib/commands/yokozuna/deleteindex.js
index c2423a3..47c1a6a 100644
--- a/lib/commands/yokozuna/deleteindex.js
+++ b/lib/commands/yokozuna/deleteindex.js
@@ -28,16 +28,16 @@ var Joi = require('joi');
 
 /**
  * Command used to Delete a Yokozuna index.
- * 
+ *
  * As a convenience, a builder class is provided:
- * 
+ *
  *     var del = DeleteIndex.Builder()
  *                  .withIndexName('index_name')
  *                  .withCallback(callback)
  *                  .build();
- *                  
+ *
  * See {{#crossLink "DeleteIndex.Builder"}}DeleteIndex.Builder{{/crossLink}}
- * 
+ *
  * @class DeleteIndex
  * @constructor
  * @param {Object} options The options for this command
@@ -48,66 +48,65 @@ var Joi = require('joi');
  * @extends CommandBase
  */
 function DeleteIndex(options, callback) {
-    
+
     CommandBase.call(this, 'RpbYokozunaIndexDeleteReq' , 'RpbDelResp', callback);
     var self = this;
     Joi.validate(options, schema, function(err, options) {
-       
+
         if (err) {
             throw err;
         }
-    
+
         self.options = options;
     });
-    
+
     this.remainingTries = 1;
 
-    
+
 }
 
 inherits(DeleteIndex, CommandBase);
 
 DeleteIndex.prototype.constructPbRequest = function() {
-  
+
     var protobuf = this.getPbReqBuilder();
-    
+
     protobuf.setName(new Buffer(this.options.indexName));
-    
+
     return protobuf;
-    
+
 };
 
 DeleteIndex.prototype.onSuccess = function(RpbDelResp) {
-    
+
     // RpbDelResp is simply null (no body)
-    
+
     this._callback(null, true);
     return true;
 };
 
 var schema = Joi.object().keys({
-    indexName: Joi.string().required(),
-    callback: Joi.func().strip().optional()
+    indexName: Joi.string().required()
 });
 
 /**
  * A builder for constructing DeleteIndex instances.
- *  
+ *
  * Rather than having to manually construct the __options__ and instantiating
  * a DeleteIndex directly, this builder may be used.
- * 
+ *
  *     var del = DeleteIndex.Builder()
  *                  .withIndexName('index_name')
  *                  .withCallback(callback)
  *                  .build();
- *       
+ *
  * @class DeleteIndex.Builder
  * @constructor
  */
 function Builder(){}
 
 Builder.prototype = {
-    
+
     /**
      * The name of the index to delete.
      * If one is not supplied, all indexes are returned.
@@ -137,7 +136,9 @@ Builder.prototype = {
      * @return {DeleteIndex}
      */
     build : function() {
-        return new DeleteIndex(this, this.callback);
+        var cb = this.callback;
+        delete this.callback;
+        return new DeleteIndex(this, cb);
     }
 };
 
diff --git a/lib/commands/yokozuna/fetchindex.js b/lib/commands/yokozuna/fetchindex.js
index 0af5ac0..261d913 100644
--- a/lib/commands/yokozuna/fetchindex.js
+++ b/lib/commands/yokozuna/fetchindex.js
@@ -28,14 +28,14 @@ var Joi = require('joi');
 
 /**
  * Command used to fetch a (Yokozuna) index or all indexes.
- * 
+ *
  * As a convenience, a builder class is provided:
- * 
+ *
  *     var fetch = FetchIndex.Builder()
  *                  .withIndexName('index_name')
  *                  .withCallback(callback)
  *                  .build();
- *                  
+ *
  * See {{#crossLink "FetchIndex.Builder"}}FetchIndex.Builder{{/crossLink}}
  *
  * @class FetchIndex
@@ -50,38 +50,38 @@ var Joi = require('joi');
  * @extends CommandBase
  */
 function FetchIndex(options, callback) {
-    
+
     CommandBase.call(this, 'RpbYokozunaIndexGetReq' , 'RpbYokozunaIndexGetResp', callback);
     var self = this;
     Joi.validate(options, schema, function(err, options) {
-       
+
         if (err) {
             throw err;
         }
-    
+
         self.options = options;
     });
-    
+
     this.remainingTries = 1;
 
-    
+
 }
 
 inherits(FetchIndex, CommandBase);
 
 FetchIndex.prototype.constructPbRequest = function() {
-  
+
     var protobuf = this.getPbReqBuilder();
-    
+
     if (this.options.indexName) {
         protobuf.setName(new Buffer(this.options.indexName));
     }
     return protobuf;
-    
+
 };
 
 FetchIndex.prototype.onSuccess = function(rpbYokozunaIndexGetResp) {
-    
+
     // If there's no indexes, Riak replies with an empty message
     var indexesToReturn;
     if (rpbYokozunaIndexGetResp) {
@@ -103,28 +103,27 @@ FetchIndex.prototype.onSuccess = function(rpbYokozunaIndexGetResp) {
 
 
 var schema = Joi.object().keys({
-    indexName: Joi.string().default(null).optional(),
-    callback: Joi.func().strip().optional()
+    indexName: Joi.string().default(null).optional()
 });
 
 /**
  * A builder for constructing FetchIndex instances.
- * 
+ *
  * Rather than having to manually construct the __options__ and instantiating
  * a FetchIndex directly, this builder may be used.
- * 
+ *
  *     var fetch = FetchIndex.Builder()
  *                  .withIndexName('index_name')
  *                  .withCallback(callback)
  *                  .build();
- *       
+ *
  * @class FetchIndex.Builder
  * @constructor
  */
 function Builder(){}
 
 Builder.prototype = {
-    
+
     /**
      * The name of the index to fetch.
      * If one is not supplied, all indexes are returned.
@@ -156,7 +155,9 @@ Builder.prototype = {
      * @return {FetchIndex}
      */
     build : function() {
-        return new FetchIndex(this, this.callback);
+        var cb = this.callback;
+        delete this.callback;
+        return new FetchIndex(this, cb);
     }
 };
 
diff --git a/lib/commands/yokozuna/fetchschema.js b/lib/commands/yokozuna/fetchschema.js
index ad8ccd2..f81e648 100644
--- a/lib/commands/yokozuna/fetchschema.js
+++ b/lib/commands/yokozuna/fetchschema.js
@@ -28,16 +28,16 @@ var Joi = require('joi');
 
 /**
  * Command used to fetch a Yokozuna schema.
- * 
+ *
  * As a convenience, a builder class is provided:
- * 
+ *
  *     var fetch = FetchSchema.Builder()
  *                  .withSchemaName('schema_name')
  *                  .withCallback(callback)
  *                  .build();
- *                  
+ *
  * See {{#crossLink "FetchSchema.Builder"}}FetchSchema.Builder{{/crossLink}}
- * 
+ *
  * @class FetchSchema
  * @constructor
  * @param {Object} options The options for this command
@@ -50,71 +50,70 @@ var Joi = require('joi');
  * @extends CommandBase
  */
 function FetchSchema(options, callback) {
-    
+
     CommandBase.call(this, 'RpbYokozunaSchemaGetReq' , 'RpbYokozunaSchemaGetResp', callback);
     var self = this;
     Joi.validate(options, schema, function(err, options) {
-       
+
         if (err) {
             throw err;
         }
-    
+
         self.options = options;
     });
-    
+
     this.remainingTries = 1;
 
-    
+
 }
 
 inherits(FetchSchema, CommandBase);
 
 FetchSchema.prototype.constructPbRequest = function() {
-  
+
     var protobuf = this.getPbReqBuilder();
-    
+
     protobuf.setName(new Buffer(this.options.schemaName));
-    
+
     return protobuf;
-    
+
 };
 
 FetchSchema.prototype.onSuccess = function(rpbYokozunaSchemaGetResp) {
-    
+
     var pbSchema = rpbYokozunaSchemaGetResp.schema;
     var schema = { name: pbSchema.name.toString('utf8') };
     if (pbSchema.content) {
         schema.content = pbSchema.content.toString('utf8');
     }
-    
-    
+
+
     this._callback(null, schema);
     return true;
 };
 
 var schema = Joi.object().keys({
-    schemaName: Joi.string().default(null).optional(),
-    callback: Joi.func().strip().optional()
+    schemaName: Joi.string().default(null).optional()
 });
 
 /**
  * A builder for constructing FetchSchema instances.
- * 
+ *
  * Rather than having to manually construct the __options__ and instantiating
  * a FetchSchema directly, this builder may be used.
- * 
+ *
  *     var fetch = FetchSchema.Builder()
  *                  .withSchemaName('schema_name')
  *                  .withCallback(callback)
  *                  .build();
- *       
+ *
  * @class FetchSchema.Builder
  * @constructor
  */
 function Builder(){}
 
 Builder.prototype = {
-    
+
     /**
      * The name of the schema to fetch.
      * @method withSchemaName
@@ -145,7 +144,9 @@ Builder.prototype = {
      * @return {FetchSchema}
      */
     build : function() {
-        return new FetchSchema(this, this.callback);
+        var cb = this.callback;
+        delete this.callback;
+        return new FetchSchema(this, cb);
     }
 };
 
diff --git a/lib/commands/yokozuna/search.js b/lib/commands/yokozuna/search.js
index 60128f7..8ad4969 100644
--- a/lib/commands/yokozuna/search.js
+++ b/lib/commands/yokozuna/search.js
@@ -27,21 +27,21 @@ var Joi = require('joi');
 
 /**
  * Command used to perform a (Yokozuna) search.
- * 
+ *
  * As a convenience, a builder class is provided:
- * 
+ *
  *      var search = new Search.Builder()
  *                      .withIndexName(myIndex)
  *                      .withQuery(myQuery)
  *                      .withNumRows(10)
  *                      .withCallback(myCallback)
  *                      .build();
- *      
+ *
  * See {{#crossLink "Search.Builder"}}Search.Builder{{/crossLink}}
- * 
+ *
  * For more information on Riak Search (Yokozuna/Solr) see:
  * [Using Search](http://docs.basho.com/riak/latest/dev/using/search/)
- *      
+ *
  * @class Search
  * @constructor
  * @param {Object} options The options for this command.
@@ -65,24 +65,24 @@ var Joi = require('joi');
  */
 function Search(options, callback)  {
     CommandBase.call(this, 'RpbSearchQueryReq', 'RpbSearchQueryResp', callback);
-    
+
     var self = this;
     Joi.validate(options, schema, function(err, options) {
-       
+
         if (err) {
             throw err;
         }
-    
+
         self.options = options;
     });
-    
+
     this.remainingTries = 1;
 }
 
 inherits(Search, CommandBase);
 
 Search.prototype.constructPbRequest = function() {
-  
+
     var protobuf = this.getPbReqBuilder();
     protobuf.index = new Buffer(this.options.indexName);
     protobuf.q = new Buffer(this.options.q);
@@ -106,9 +106,9 @@ Search.prototype.constructPbRequest = function() {
     for (var i = 0; i < this.options.returnFields.length; i++) {
         protobuf.fl.push(new Buffer(this.options.returnFields[i]));
     }
-    
+
     return protobuf;
-    
+
 };
 
 Search.prototype.onSuccess = function(rpbSearchQueryResp) {
@@ -119,18 +119,18 @@ Search.prototype.onSuccess = function(rpbSearchQueryResp) {
         for (var j = 0; j < rpbSearchQueryResp.docs[i].fields.length; j++) {
             var key = rpbSearchQueryResp.docs[i].fields[j].key.toString('utf8');
             var value = rpbSearchQueryResp.docs[i].fields[j].value.toString('utf8');
-            // Search and MapReduce are effectively broken with the PB API because 
+            // Search and MapReduce are effectively broken with the PB API because
             // everything is returned as a string.
             if (!isNaN(value)) {
-                // it's really a number. 
+                // it's really a number.
                 value = +value;
             } else if (value === 'null') {
                 // It's actually null
                 value = null;
             } else {
-                // might also be a boolean. 
+                // might also be a boolean.
                 value = value === 'true' || (value === 'false' ? false : value);
-            } 
+            }
             //Support multiple values for the same key
             if (doc.hasOwnProperty(key)) {
                 if (doc[key].constructor === Array) {
@@ -147,7 +147,7 @@ Search.prototype.onSuccess = function(rpbSearchQueryResp) {
     var result = { numFound : rpbSearchQueryResp.num_found,
                    maxScore : rpbSearchQueryResp.max_score,
                    docs: docsToReturn };
-               
+
     this._callback(null, result);
     return true;
 
@@ -163,30 +163,29 @@ var schema = Joi.object().keys({
     defaultField: Joi.string().default(null).optional(),
     defaultOperation: Joi.string().default(null).optional(),
     returnFields: Joi.array().default([]).optional(),
-    presort: Joi.string().default(null).optional(),
-    callback: Joi.func().strip().optional()
+    presort: Joi.string().default(null).optional()
 });
 
 /**
  * A builder for constructing Search instances.
- * 
+ *
  * Rather than having to manually construct the __options__ and instantiating
  * a Search directly, this builder may be used.
- * 
+ *
  *     var search = new Search.Builder()
  *                    .withIndexName(myIndex)
  *                    .withQuery(myQuery)
  *                    .withNumRows(10)
  *                    .withCallback(myCallback)
  *                    .build();
- *       
+ *
  * @class Search.Builder
  * @constructor
  */
 function Builder() {}
 
 Builder.prototype = {
-  
+
     /**
      * Set the index name used for this search.
      * @method withIndexName
@@ -199,8 +198,8 @@ Builder.prototype = {
     },
     /**
      * Set the Solr query string.
-     * All distributed Solr queries are supported, which actually 
-     * includes most of the single-node Solr queries. 
+     * All distributed Solr queries are supported, which actually
+     * includes most of the single-node Solr queries.
      * @method withQuery
      * @param {String} queryString the query
      * @chainable
@@ -318,9 +317,11 @@ Builder.prototype = {
     * @return {Search}
     */
    build : function() {
-       return new Search(this, this.callback);
+        var cb = this.callback;
+        delete this.callback;
+        return new Search(this, cb);
    }
-    
+
 };
 
 module.exports = Search;
diff --git a/lib/commands/yokozuna/storeindex.js b/lib/commands/yokozuna/storeindex.js
index 3474b17..9bbc20b 100644
--- a/lib/commands/yokozuna/storeindex.js
+++ b/lib/commands/yokozuna/storeindex.js
@@ -27,51 +27,51 @@ var RpbYokozunaIndex = require('../../protobuf/riakprotobuf').getProtoFor('RpbYo
 
 /**
  * Command used to store a Yokozuna index.
- * 
+ *
  * As a convenience, a builder class is provided:
- * 
+ *
  *     var store = StoreIndex.Builder()
  *                  .withIndexName('index_name')
  *                  .withSchemaName('my_schema')
  *                  .withCallback(callback)
  *                  .build();
- *                  
+ *
  * See {{#crossLink "StoreIndex.Builder"}}StoreIndex.Builder{{/crossLink}}
- * 
+ *
  * @class StoreIndex
  * @constructor
  * @param {Object} options The options for this command
- * @param {String} options.indexName The name of the index. 
- * @param {String} [options.schemaName=_yz_default] The name of the schema for this index. 
+ * @param {String} options.indexName The name of the index.
+ * @param {String} [options.schemaName=_yz_default] The name of the schema for this index.
  * @param {Function} callback The callback to be executed when the operation completes.
  * @param {String} callback.err An error message. Will be null if no error.
  * @param {Boolean} callback.response The operation either succeeds or errors. This will be true.
  * @extends CommandBase
  */
 function StoreIndex(options, callback) {
-    
+
     CommandBase.call(this, 'RpbYokozunaIndexPutReq' , 'RpbPutResp', callback);
     var self = this;
     Joi.validate(options, schema, function(err, options) {
-       
+
         if (err) {
             throw err;
         }
-    
+
         self.options = options;
     });
-    
+
     this.remainingTries = 1;
 
-    
+
 }
 
 inherits(StoreIndex, CommandBase);
 
 StoreIndex.prototype.constructPbRequest = function() {
-  
+
     var protobuf = this.getPbReqBuilder();
-    
+
     var pbIndex = new RpbYokozunaIndex();
     pbIndex.setName(new Buffer(this.options.indexName));
     if (this.options.schemaName) {
@@ -79,13 +79,13 @@ StoreIndex.prototype.constructPbRequest = function() {
     }
     protobuf.index = pbIndex;
     return protobuf;
-    
+
 };
 
 StoreIndex.prototype.onSuccess = function(RpbPutResp) {
-    
+
     // RpbPutResp is simply null (no body)
-    
+
     this._callback(null, true);
     return true;
 };
@@ -93,29 +93,28 @@ StoreIndex.prototype.onSuccess = function(RpbPutResp) {
 
 var schema = Joi.object().keys({
     indexName: Joi.string().required(),
-    schemaName: Joi.string().default(null).optional(),
-    callback: Joi.func().strip().optional()
+    schemaName: Joi.string().default(null).optional()
 });
 
 /**
  * A builder for constructing StoreIndex instances.
- * 
+ *
  * Rather than having to manually construct the __options__ and instantiating
  * a StoreIndex directly, this builder may be used.
- * 
+ *
  *     var store = StoreIndex.Builder()
  *                  .withIndexName('index_name')
  *                  .withSchemaName('my_schema')
  *                  .withCallback(callback)
  *                  .build();
- *       
+ *
  * @class StoreIndex.Builder
  * @constructor
  */
 function Builder(){}
 
 Builder.prototype = {
-    
+
     /**
      * The name of the index to store.
      * @method withIndexName
@@ -155,7 +154,9 @@ Builder.prototype = {
      * @return {StoreIndex}
      */
     build : function() {
-        return new StoreIndex(this, this.callback);
+        var cb = this.callback;
+        delete this.callback;
+        return new StoreIndex(this, cb);
     }
 };
 
diff --git a/lib/commands/yokozuna/storeschema.js b/lib/commands/yokozuna/storeschema.js
index b782d33..5e7b059 100644
--- a/lib/commands/yokozuna/storeschema.js
+++ b/lib/commands/yokozuna/storeschema.js
@@ -28,17 +28,17 @@ var RpbYokozunaSchema = require('../../protobuf/riakprotobuf').getProtoFor('RpbY
 
 /**
  * Command used to store a Yokozuna schema.
- * 
+ *
  * As a convenience, a builder class is provided:
- * 
+ *
  *     var store = StoreSchema.Builder()
  *                  .withSchemaName('schema_name')
  *                  .withSchema(mySchemaXML)
  *                  .withCallback(callback)
  *                  .build();
- *                  
+ *
  * See {{#crossLink "StoreSchema.Builder"}}StoreSchema.Builder{{/crossLink}}
- * 
+ *
  * @class StoreSchema
  * @constructor
  * @param {Object} options The options for this command
@@ -50,39 +50,39 @@ var RpbYokozunaSchema = require('../../protobuf/riakprotobuf').getProtoFor('RpbY
  * @extends CommandBase
  */
 function StoreSchema(options, callback) {
-    
+
     CommandBase.call(this, 'RpbYokozunaSchemaPutReq' , 'RpbPutResp', callback);
     var self = this;
     Joi.validate(options, schema, function(err, options) {
-       
+
         if (err) {
             throw err;
         }
-    
+
         self.options = options;
     });
-    
+
     this.remainingTries = 1;
 
-    
+
 }
 
 inherits(StoreSchema, CommandBase);
 
 StoreSchema.prototype.constructPbRequest = function() {
-  
+
     var protobuf = this.getPbReqBuilder();
     var pbSchema = new RpbYokozunaSchema();
     pbSchema.name = new Buffer(this.options.schemaName);
     pbSchema.content = new Buffer(this.options.schema);
     protobuf.schema = pbSchema;
-    
+
     return protobuf;
-    
+
 };
 
 StoreSchema.prototype.onSuccess = function(rpbPutResp) {
-    
+
     // rpbPutResp will be null (no body)
     this._callback(null, true);
     return true;
@@ -90,29 +90,28 @@ StoreSchema.prototype.onSuccess = function(rpbPutResp) {
 
 var schema = Joi.object().keys({
     schemaName: Joi.string().required(),
-    schema: Joi.string().required(),
-    callback: Joi.func().strip().optional()
+    schema: Joi.string().required()
 });
 
 /**
  * A builder for constructing StoreSchema instances.
- * 
+ *
  * Rather than having to manually construct the __options__ and instantiating
  * a StoreSchema directly, this builder may be used.
- * 
+ *
  *     var store = StoreSchema.Builder()
  *                  .withSchemaName('schema_name')
  *                  .withSchema(mySchemaXML)
  *                  .withCallback(callback)
  *                  .build();
- *       
+ *
  * @class StoreSchema.Builder
  * @constructor
  */
 function Builder(){}
 
 Builder.prototype = {
-    
+
     /**
      * The name of the schema.
      * @method withSchemaName
@@ -151,7 +150,9 @@ Builder.prototype = {
      * @return {StoreSchema}
      */
     build : function() {
-        return new StoreSchema(this, this.callback);
+        var cb = this.callback;
+        delete this.callback;
+        return new StoreSchema(this, cb);
     }
 };
 
diff --git a/lib/core/authreq.js b/lib/core/authreq.js
index 0b2eb86..c8a355a 100644
--- a/lib/core/authreq.js
+++ b/lib/core/authreq.js
@@ -20,14 +20,14 @@ var Joi = require('joi');
 var logger = require('winston');
 
 /**
- * 
+ *
  * @module Core
  */
 
 /**
  * Provides the AuthReq class
  * Command used to authenticate with Riak.
- * 
+ *
  * @class AuthReq
  * @constructor
  * @param {Object} options
@@ -35,7 +35,7 @@ var logger = require('winston');
  * @param {String} options.password the password with which to authenticate (optional)
  * @param {Function} callback the function to call when the command completes or errors
  * @extends CommandBase
- */ 
+ */
 function AuthReq(options, callback) {
 
     CommandBase.call(this, 'RpbAuthReq', 'RpbAuthResp', callback);
@@ -69,11 +69,10 @@ AuthReq.prototype.onSuccess = function(rpbAuthResp) {
      */
     return true;
 };
-    
+
 var schema = Joi.object().keys({
     user: Joi.string().required(),
-    password: Joi.string().optional().allow('').default(''),
-    callback: Joi.func().strip().optional()
+    password: Joi.string().optional().allow('').default('')
 });
 
 module.exports = AuthReq;
diff --git a/lib/core/starttls.js b/lib/core/starttls.js
index cbbe6c2..e05a043 100644
--- a/lib/core/starttls.js
+++ b/lib/core/starttls.js
@@ -28,7 +28,7 @@ var Joi = require('joi');
  * @constructor
  * @param {Function} callback the function to call when the command completes or errors
  * @extends CommandBase
- */ 
+ */
 function StartTls(callback) {
     CommandBase.call(this, 'RpbStartTls', 'RpbStartTls', callback);
 
@@ -44,14 +44,14 @@ StartTls.prototype.constructPbRequest = function() {
 };
 
 StartTls.prototype.onSuccess = function(rpbStartTlsResp) {
-        
+
     if (rpbStartTlsResp === null) {
         // TODO ERROR
     }
 
     return true;
 };
-    
+
 
 module.exports = StartTls;
 


Test patch:
diff --git a/test/unit/commandbase.js b/test/unit/commandbase.js
new file mode 100644
index 0000000..9b83746
--- /dev/null
+++ b/test/unit/commandbase.js
@@ -0,0 +1,374 @@
+﻿/*
+ * Copyright 2015 Basho Technologies, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+var assert = require('assert');
+var logger = require('winston');
+
+var Riak = require('../../lib/client');
+var CommandBase = require('../../lib/commands/commandbase');
+var inherits = require('util').inherits;
+var Joi = require('joi');
+
+function TestCommand(options, callback) {
+    CommandBase.call(this, 'RpbGetReq', 'RpbGetResp', callback);
+    var self = this;
+    Joi.validate(options, schema, function(err, options) {
+
+        if (err) {
+            throw err;
+        }
+
+        self.options = options;
+    });
+}
+
+inherits(TestCommand, CommandBase);
+
+var schema = Joi.object().keys({
+   bucketType: Joi.string().default('default'),
+   bucket: Joi.string().required(),
+   key: Joi.string().required()
+});
+
+function TestBuilder() {}
+
+TestBuilder.prototype = {
+    withBucket : function(bucket) {
+        this.bucket = bucket;
+        return this;
+    },
+    withKey : function(key) {
+        this.key = key;
+        return this;
+    },
+    withCallback : function(callback) {
+        this.callback = callback;
+        return this;
+    },
+    build : function() {
+        var cb = this.callback;
+        delete this.callback;
+        return new TestCommand(this, cb);
+    }
+};
+
+describe('CommandBase', function() {
+
+    function cb(err, rslt) { }
+
+    describe('TestCommand', function() {
+
+        it('should use callback passed as ctor argument', function(done) {
+            var options = {
+                bucketType: 'maps',
+                bucket: 'foo',
+                key: 'bar'
+            };
+            assert.doesNotThrow(function () {
+                var cmd = new TestCommand(options, cb);
+                assert(cmd.callback == cb);
+                done();
+            });
+        });
+
+        it('should use callback via Builder', function(done) {
+            assert.doesNotThrow(function () {
+                var cmd = new TestBuilder()
+                    .withBucket('foo')
+                    .withKey('bar')
+                    .withCallback(cb)
+                    .build();
+                assert(cmd.callback == cb);
+                done();
+            });
+        });
+
+        it('should throw when callback not passed to ctor', function(done) {
+            var options = {
+                bucketType: 'maps',
+                bucket: 'foo',
+                key: 'bar'
+            };
+            assert.throws(function () {
+                var cmd = new TestCommand(options);
+            });
+            done();
+        });
+
+        it('should throw when callback passed via options', function(done) {
+            var options = {
+                bucketType: 'maps',
+                bucket: 'foo',
+                key: 'bar',
+                callback: cb
+            };
+            assert.throws(function () {
+                var cmd = new TestCommand(options, cb);
+            });
+            done();
+        });
+
+    });
+
+    describe('Commands', function() {
+        var default_options = {
+            bucketType: 'baz',
+            bucket: 'foo',
+            key: 'bar',
+            callback: cb
+        };
+
+        var default_builder_func = function (b) {
+            b.withBucketType(default_options.bucketType);
+            b.withBucket(default_options.bucket);
+            b.withKey(default_options.key);
+        };
+
+        var updateMapOp = new Riak.Commands.CRDT.UpdateMap.MapOperation();
+
+        var commands = {
+            'YZ.DeleteIndex' : {
+                    options : {
+                        indexName: 'frazzle',
+                        callback: cb
+                    },
+                    builder_func: function (b) {
+                        b.withIndexName('frazzle');
+                    }
+                },
+            'YZ.FetchIndex' : {
+                    options : {
+                        indexName: 'frazzle',
+                        callback: cb
+                    },
+                    builder_func: function (b) {
+                        b.withIndexName('frazzle');
+                    }
+                },
+            'YZ.FetchSchema' : {
+                    options : {
+                        schemaName: 'frazzle',
+                        callback: cb
+                    },
+                    builder_func: function (b) {
+                        b.withSchemaName('frazzle');
+                    }
+                },
+            'YZ.Search' : {
+                    options : {
+                        q : '*:*',
+                        indexName: 'frazzle',
+                        callback: cb
+                    },
+                    builder_func: function (b) {
+                        b.withIndexName('frazzle');
+                        b.withQuery('*:*');
+                    }
+                },
+            'YZ.StoreIndex' : {
+                    options : {
+                        indexName: 'frazzle',
+                        callback: cb
+                    },
+                    builder_func: function (b) {
+                        b.withIndexName('frazzle');
+                    }
+                },
+            'YZ.StoreSchema' : {
+                    options : {
+                        schemaName: 'frazzle',
+                        schema: '<fauxml></fauxml>',
+                        callback: cb
+                    },
+                    builder_func: function (b) {
+                        b.withSchemaName('frazzle');
+                        b.withSchema('<fauxml></fauxml>');
+                    }
+                },
+            'CRDT.FetchCounter' : {
+                    options : default_options,
+                    builder_func : default_builder_func
+                },
+            'CRDT.FetchMap' : {
+                    options : default_options,
+                    builder_func : default_builder_func
+                },
+            'CRDT.FetchSet' : {
+                    options : default_options,
+                    builder_func : default_builder_func
+                },
+            'CRDT.UpdateCounter' : {
+                    options : {
+                        bucketType: default_options.bucketType,
+                        bucket: default_options.bucket,
+                        key: default_options.key,
+                        increment: 1,
+                        callback: cb
+                    },
+                    builder_func: function (b) {
+                        b.withBucketType(default_options.bucketType);
+                        b.withBucket(default_options.bucket);
+                        b.withKey(default_options.key);
+                        b.withIncrement(1);
+                    }
+                },
+            'CRDT.UpdateMap' : {
+                    options : {
+                        bucketType: default_options.bucketType,
+                        bucket: default_options.bucket,
+                        key: default_options.key,
+                        op: updateMapOp,
+                        callback: cb
+                    },
+                    builder_func: function (b) {
+                        b.withBucketType(default_options.bucketType);
+                        b.withBucket(default_options.bucket);
+                        b.withKey(default_options.key);
+                        b.withMapOperation(updateMapOp);
+                    }
+                },
+            'CRDT.UpdateSet' : {
+                    options : default_options,
+                    builder_func : default_builder_func
+                },
+            'KV.DeleteValue' : {
+                    options : default_options,
+                    builder_func: function (b) {
+                        b.withBucket(default_options.bucket);
+                        b.withKey(default_options.key);
+                    }
+                },
+            'KV.FetchBucketProps' : {
+                    options : {
+                        bucketType: default_options.bucketType,
+                        bucket: default_options.bucket,
+                        callback: cb
+                    },
+                    builder_func: function (b) {
+                        b.withBucket(default_options.bucket);
+                    }
+                },
+            'KV.FetchValue' : {
+                    options : default_options,
+                    builder_func: function (b) {
+                        b.withBucket(default_options.bucket);
+                        b.withKey(default_options.key);
+                    }
+                },
+            'KV.ListBuckets' : {
+                    options : {
+                        bucketType: default_options.bucketType,
+                        callback: cb
+                    }
+                },
+            'KV.ListKeys' : {
+                    options : {
+                        bucketType: default_options.bucketType,
+                        bucket: default_options.bucket,
+                        callback: cb
+                    },
+                    builder_func: function (b) {
+                        b.withBucket(default_options.bucket);
+                    }
+                },
+            'KV.SecondaryIndexQuery' : {
+                    options : {
+                        bucketType: default_options.bucketType,
+                        bucket: default_options.bucket,
+                        indexName: 'frazzle_bin',
+                        indexKey: '12345',
+                        callback: cb
+                    },
+                    builder_func: function (b) {
+                        b.withBucketType(default_options.bucketType);
+                        b.withBucket(default_options.bucket);
+                        b.withIndexName('frazzle_bin');
+                        b.withIndexKey('12345');
+                    }
+                },
+            'KV.StoreBucketProps' : {
+                    options : {
+                        bucketType: default_options.bucketType,
+                        bucket: default_options.bucket,
+                        callback: cb
+                    },
+                    builder_func: function (b) {
+                        b.withBucket(default_options.bucket);
+                    }
+                },
+            'KV.StoreValue' : {
+                    options : {
+                        bucketType: default_options.bucketType,
+                        bucket: default_options.bucket,
+                        key: default_options.key,
+                        value: 'blargh',
+                        callback: cb
+                    },
+                    builder_func : function (b) {
+                        b.withBucketType(default_options.bucketType);
+                        b.withBucket(default_options.bucket);
+                        b.withKey(default_options.key);
+                        b.withContent('blargh');
+                    }
+                },
+        };
+
+        it('should throw when callback passed via options', function(done) {
+            Object.keys(commands).forEach(function (cmd_name) {
+                var options = commands[cmd_name].options;
+                var eval_str = "new Riak.Commands." + cmd_name + "(options, cb)";
+                var e_message = null;
+                try {
+                    var cmd = eval(eval_str); // jshint ignore:line
+                } catch (e) {
+                    if (e.message !== '"callback" is not allowed') {
+                        logger.error("%s ctor threw: %s", cmd_name, e.message);
+                        throw e;
+                    }
+                }
+            });
+            done();
+        });
+
+        it('should use callback via Builder', function(done) {
+            Object.keys(commands).forEach(function (cmd_name) {
+                var options = commands[cmd_name].options;
+                var builder_func = commands[cmd_name].builder_func;
+
+                var eval_str = "new Riak.Commands." + cmd_name + ".Builder()";
+                var builder = eval(eval_str); // jshint ignore:line
+                builder.withCallback(cb);
+
+                if (builder_func) {
+                    builder_func(builder);
+                }
+
+                var cmd;
+                try {
+                    cmd = builder.build();
+                } catch (e) {
+                    logger.error("%s builder.build() threw: %s", cmd_name, e.message);
+                    throw e;
+                }
+                assert(cmd.callback == cb);
+            });
+            done();
+        });
+
+    });
+
+});
+
diff --git a/test/unit/crdt/updatecounter.js b/test/unit/crdt/updatecounter.js
index 2eb9eb3..a3a1428 100644
--- a/test/unit/crdt/updatecounter.js
+++ b/test/unit/crdt/updatecounter.js
@@ -105,4 +105,5 @@ describe('UpdateCounter', function() {
             update.onRiakError(rpbErrorResp);
         });
     });
-});
\ No newline at end of file
+});
+
diff --git a/test/unit/crdt/updatemap.js b/test/unit/crdt/updatemap.js
index 77a1fbe..804047c 100644
--- a/test/unit/crdt/updatemap.js
+++ b/test/unit/crdt/updatemap.js
@@ -25,13 +25,13 @@ var RpbErrorResp = require('../../../lib/protobuf/riakprotobuf').getProtoFor('Rp
 var assert = require('assert');
 
 describe('UpdateMap', function() {
-    
+
     describe('UpdateMap', function() {
-    
+
         it('should build a DtUpdateReq correctly', function(done) {
-           
+
            var mapOp = new UpdateMap.MapOperation();
-           
+
             mapOp.incrementCounter('counter_1', 50)
                 .removeCounter('counter_2')
                 .addToSet('set_1', 'set_value_1')
@@ -42,7 +42,7 @@ describe('UpdateMap', function() {
                 .setFlag('flag_1', true)
                 .removeFlag('flag_2')
                 .removeMap('map_3');
-        
+
             mapOp.map('map_2').incrementCounter('counter_1', 50)
                 .removeCounter('counter_2')
                 .addToSet('set_1', new Buffer('set_value_1'))
@@ -54,8 +54,8 @@ describe('UpdateMap', function() {
                 .removeFlag('flag_2')
                 .removeMap('map_3')
                 .map('map_2');
-        
-           
+
+
             var update = new UpdateMap.Builder()
                 .withBucketType('maps')
                 .withBucket('myBucket')
@@ -69,9 +69,9 @@ describe('UpdateMap', function() {
                 .withReturnBody(true)
                 .withTimeout(20000)
                 .build();
-        
+
             var protobuf = update.constructPbRequest();
-                        
+
             assert.equal(protobuf.getType().toString('utf8'), 'maps');
             assert.equal(protobuf.getBucket().toString('utf8'), 'myBucket');
             assert.equal(protobuf.getKey().toString('utf8'), 'map_1');
@@ -81,9 +81,9 @@ describe('UpdateMap', function() {
             assert.equal(protobuf.getReturnBody(), true);
             assert.equal(protobuf.getTimeout(), 20000);
             assert.equal(protobuf.getContext().toString('utf8'), '1234');
-            
+
             mapOp = protobuf.op.map_op;
-            
+
             var verifyRemoves = function(removes) {
                 assert.equal(removes.length, 5);
                 var i;
@@ -118,19 +118,19 @@ describe('UpdateMap', function() {
                             break;
                     }
                 }
-                
+
                 assert(counterRemoved);
                 assert(setRemoved);
                 assert(registerRemoved);
                 assert(flagRemoved);
                 assert(mapRemoved);
-                
+
             };
-            
+
             verifyRemoves(mapOp.removes);
-            
+
             var verifyUpdates = function(updates) {
-              
+
                 var i;
                 var counterIncremented = false;
                 var setAddedTo = false;
@@ -151,12 +151,12 @@ describe('UpdateMap', function() {
                                 assert.equal(updates[i].field.name.toString('utf8'), 'set_1');
                                 assert.equal(updates[i].set_op.adds[0].toString('utf8'),'set_value_1');
                                 setAddedTo = true;
-                                
+
                             } else {
                                 assert.equal(updates[i].field.name.toString('utf8'), 'set_2');
                                 assert.equal(updates[i].set_op.removes[0].toString('utf8'),'set_value_2');
                                 setRemovedFrom = true;
-                            }   
+                            }
                             break;
                         case MapField.MapFieldType.MAP:
                             assert.equal(updates[i].field.name.toString('utf8'), 'map_2');
@@ -177,38 +177,38 @@ describe('UpdateMap', function() {
                             break;
                     }
                 }
-                
+
                 assert(counterIncremented);
                 assert(setAddedTo);
                 assert(setRemovedFrom);
                 assert(registerSet);
                 assert(flagSet);
                 assert(mapAdded);
-                
+
                 return mapUpdate;
-                
+
             };
-            
+
             verifyRemoves(mapOp.removes);
             var innerMapUpdate = verifyUpdates(mapOp.updates);
             verifyUpdates(innerMapUpdate.map_op.updates);
             verifyRemoves(innerMapUpdate.map_op.removes);
-            
+
             // perform happy dance
-            
+
             done();
-            
+
         });
-        
+
         it('should take a DtUpdateResp and call the users callback with the response', function(done) {
-           
+
             var dtUpdateResp = new DtUpdateResp();
             dtUpdateResp.setKey(new Buffer('riak_generated_key'));
             dtUpdateResp.setContext(new Buffer('1234'));
-            
+
             var createMapEntries = function() {
                 var mapEntries = [];
-                
+
                 var mapEntry = new MapEntry();
                 var mapField = new MapField();
                 mapField.setType(MapField.MapFieldType.COUNTER);
@@ -216,7 +216,7 @@ describe('UpdateMap', function() {
                 mapEntry.setField(mapField);
                 mapEntry.setCounterValue(50);
                 mapEntries.push(mapEntry);
-                
+
                 mapEntry = new MapEntry();
                 mapField = new MapField();
                 mapField.setType(MapField.MapFieldType.SET);
@@ -224,7 +224,7 @@ describe('UpdateMap', function() {
                 mapEntry.setField(mapField);
                 mapEntry.set_value.push.apply(mapEntry.set_value, [ByteBuffer.fromUTF8('value_1'), ByteBuffer.fromUTF8('value_2')]);
                 mapEntries.push(mapEntry);
-                
+
                 mapEntry = new MapEntry();
                 mapField = new MapField();
                 mapField.setType(MapField.MapFieldType.REGISTER);
@@ -232,7 +232,7 @@ describe('UpdateMap', function() {
                 mapEntry.setField(mapField);
                 mapEntry.setRegisterValue(ByteBuffer.fromUTF8('1234'));
                 mapEntries.push(mapEntry);
-                
+
                 mapEntry = new MapEntry();
                 mapField = new MapField();
                 mapField.setType(MapField.MapFieldType.FLAG);
@@ -240,27 +240,27 @@ describe('UpdateMap', function() {
                 mapEntry.setField(mapField);
                 mapEntry.setFlagValue(true);
                 mapEntries.push(mapEntry);
-                
+
                 return mapEntries;
 
             };
-            
+
             dtUpdateResp.map_value.push.apply(dtUpdateResp.map_value, createMapEntries());
-            
+
             var mapEntry = new MapEntry();
             var mapField = new MapField();
             mapField.setType(MapField.MapFieldType.MAP);
             mapField.setName(new Buffer('map_1'));
             mapEntry.setField(mapField);
             mapEntry.map_value.push.apply(mapEntry.map_value, createMapEntries());
-            
+
             dtUpdateResp.map_value.push(mapEntry);
-            
+
             var callback = function(err, resp) {
                 assert(resp !== null);
                 assert.equal(resp.generatedKey.toString('utf8'), 'riak_generated_key');
                 assert.equal(resp.context.toString('utf8'), '1234');
-                
+
                 var verifyMap = function(map) {
                     assert.equal(map.counters.counter_1, 50);
                     assert.equal(map.sets.set_1[0], 'value_1');
@@ -268,16 +268,16 @@ describe('UpdateMap', function() {
                     assert.equal(map.registers.register_1.toString('utf8'), '1234');
                     assert.equal(map.flags.flag_1, true);
                 };
-            
+
                 verifyMap(resp.map);
                 verifyMap(resp.map.maps.map_1);
                 done();
-            
+
             };
-            
+
             var mapOp = new UpdateMap.MapOperation();
-            
-            
+
+
             var update = new UpdateMap.Builder()
                 .withBucketType('maps')
                 .withBucket('myBucket')
@@ -285,22 +285,22 @@ describe('UpdateMap', function() {
                 .withMapOperation(mapOp)
                 .withCallback(callback)
                 .build();
-        
+
             update.onSuccess(dtUpdateResp);
-            
+
         });
-        
+
         it ('should take a RpbErrorResp and call the users callback with the error message', function(done) {
             var rpbErrorResp = new RpbErrorResp();
             rpbErrorResp.setErrmsg(new Buffer('this is an error'));
-           
+
             var callback = function(err, response) {
                 if (err) {
                     assert.equal(err,'this is an error');
                     done();
                 }
             };
-            
+
             var mapOp = new UpdateMap.MapOperation();
             var update = new UpdateMap.Builder()
                 .withBucketType('maps')
@@ -309,22 +309,22 @@ describe('UpdateMap', function() {
                 .withMapOperation(mapOp)
                 .withCallback(callback)
                 .build();
-        
+
             update.onRiakError(rpbErrorResp);
         });
-        
+
     });
-    
+
     describe('MapOperation', function() {
-        
+
         it('should add counter increments', function(done) {
-            
+
             var op = new UpdateMap.MapOperation();
-            
+
             op.incrementCounter('counter_1', 5);
             op.incrementCounter('counter_2', 5);
             op.incrementCounter('counter_2', -10);
-            
+
             assert.equal(op.counters.increment.length, 2);
             assert.equal(op.counters.increment[0].key, 'counter_1');
             assert.equal(op.counters.increment[0].increment, 5);
@@ -332,38 +332,38 @@ describe('UpdateMap', function() {
             assert.equal(op.counters.increment[1].increment, -5);
             done();
         });
-        
+
         it('should invalidate counter increment on remove', function(done) {
-           
+
             var op = new UpdateMap.MapOperation();
-            
+
             op.incrementCounter('counter_1', 5);
             op.removeCounter('counter_1');
-            
+
             assert.equal(op.counters.increment.length, 0);
             assert.equal(op.counters.remove.length, 1);
             assert.equal(op.counters.remove[0], 'counter_1');
             assert(op._hasRemoves());
             done();
-            
+
         });
-        
+
         it('should invalidate counter remove on increment', function(done) {
             var op = new UpdateMap.MapOperation();
-            
+
             op.removeCounter('counter_1');
             op.incrementCounter('counter_1', 5);
             assert.equal(op.counters.remove.length, 0);
             assert.equal(op.counters.increment[0].key, 'counter_1');
             assert.equal(op.counters.increment[0].increment, 5);
             done();
-            
+
         });
-        
+
         it('should add set adds', function(done) {
-           
+
             var op = new UpdateMap.MapOperation();
-            
+
             op.addToSet('set_1', 'value_1');
             op.addToSet('set_1', 'value_2');
             op.addToSet('set_2', 'value_1');
@@ -376,13 +376,13 @@ describe('UpdateMap', function() {
             assert.equal(op.sets.adds[1].key, 'set_2');
             assert.equal(op.sets.adds[1].add[0], 'value_1');
             done();
-            
+
         });
-        
+
         it('should add set removes', function(done) {
-            
+
             var op = new UpdateMap.MapOperation();
-            
+
             op.removeFromSet('set_1', 'value_1');
             op.removeFromSet('set_1', 'value_2');
             op.removeFromSet('set_2', 'value_1');
@@ -396,18 +396,18 @@ describe('UpdateMap', function() {
             assert.equal(op.sets.removes[1].remove[0], 'value_1');
             assert(op._hasRemoves());
             done();
-            
+
         });
-        
+
         it('should invalidate adding to a set on a remove set', function(done) {
-           
+
            var op = new UpdateMap.MapOperation();
-           
+
            op.addToSet('set_1', 'value_1');
            op.addToSet('set_2', 'value_1');
            op.removeSet('set_1');
            op.removeSet('set_3');
-           
+
            assert.equal(op.sets.adds.length, 1);
            assert.equal(op.sets.adds[0].key, 'set_2');
            assert.equal(op.sets.remove.length, 2);
@@ -415,18 +415,18 @@ describe('UpdateMap', function() {
            assert.equal(op.sets.remove[1], 'set_3');
            assert(op._hasRemoves());
            done();
-           
+
         });
-        
+
         it('should invalidate removing from a set on a remove set', function(done) {
-           
+
            var op = new UpdateMap.MapOperation();
-           
+
            op.removeFromSet('set_1', 'value_1');
            op.removeFromSet('set_2', 'value_1');
            op.removeSet('set_1');
            op.removeSet('set_3');
-           
+
            assert.equal(op.sets.removes.length, 1);
            assert.equal(op.sets.removes[0].key, 'set_2');
            assert.equal(op.sets.remove.length, 2);
@@ -434,13 +434,13 @@ describe('UpdateMap', function() {
            assert.equal(op.sets.remove[1], 'set_3');
            assert(op._hasRemoves());
            done();
-            
+
         });
-        
+
         it('should invalidate removing a set on an add to set', function(done) {
-           
+
             var op = new UpdateMap.MapOperation();
-            
+
             op.removeSet('set_1');
             op.removeSet('set_3');
             assert.equal(op.sets.remove.length, 2);
@@ -451,13 +451,13 @@ describe('UpdateMap', function() {
             assert(op._hasRemoves());
 
             done();
-            
+
         });
-        
+
         it('should invalidate removing a set on a remove from set', function(done) {
-            
+
             var op = new UpdateMap.MapOperation();
-            
+
             op.removeSet('set_1');
             op.removeSet('set_3');
             assert.equal(op.sets.remove.length, 2);
@@ -468,39 +468,39 @@ describe('UpdateMap', function() {
             assert(op._hasRemoves());
 
             done();
-            
+
         });
-        
+
         it('should add registers', function(done) {
-           
+
            var op = new UpdateMap.MapOperation();
-           
+
            op.setRegister('register_1', new Buffer('value_1'));
            op.setRegister('register_2', new Buffer('value_2'));
-           
+
            assert.equal(op.registers.set.length, 2);
            assert.equal(op.registers.set[0].key, 'register_1');
            assert.equal(op.registers.set[0].value.toString('utf8'), 'value_1');
            assert.equal(op.registers.set[1].key, 'register_2');
            assert.equal(op.registers.set[1].value.toString('utf8'), 'value_2');
-           
+
            op.setRegister('register_1', new Buffer('value_3'));
            assert.equal(op.registers.set[0].key, 'register_1');
            assert.equal(op.registers.set[0].value.toString('utf8'), 'value_3');
            done();
-           
-            
+
+
         });
-        
+
         it('should invalidate register sets on removes', function(done) {
-            
+
             var op = new UpdateMap.MapOperation();
-            
+
             op.setRegister('register_1', new Buffer('value_1'));
             op.setRegister('register_2', new Buffer('value_2'));
-            
+
             op.removeRegister('register_1');
-            
+
             assert.equal(op.registers.set.length, 1);
             assert.equal(op.registers.set[0].key, 'register_2');
             assert.equal(op.registers.set[0].value.toString('utf8'), 'value_2');
@@ -509,16 +509,16 @@ describe('UpdateMap', function() {
             assert(op._hasRemoves());
             done();
         });
-        
+
         if('should invalidate register removes on register sets', function(done) {
-            
+
             var op = new UpdateMap.MapOperation();
             op.removeRegister('register_1');
             op.removeRegister('register_2');
             assert.equal(op.registers.remove.length, 2);
             assert.equal(op.registers.remove[0], 'register_1');
             assert.equal(op.registers.remove[1], 'register_2');
-            
+
             op.setRegister('register_1', new Buffer('value_1'));
             assert.equal(op.registers.set.length, 1);
             assert.equal(op.registers.remove.length, 1);
@@ -526,31 +526,31 @@ describe('UpdateMap', function() {
             assert(op._hasRemoves());
             done();
         });
-        
+
         it('should set flags', function(done) {
-           
+
             var op = new UpdateMap.MapOperation();
-            
+
             op.setFlag('flag_1', true);
             op.setFlag('flag_2', false);
-            
+
             assert.equal(op.flags.set.length, 2);
             assert.equal(op.flags.set[0].key, 'flag_1');
             assert.equal(op.flags.set[1].key, 'flag_2');
             assert.equal(op.flags.set[0].state, true);
             assert.equal(op.flags.set[1].state, false);
-            
+
             op.setFlag('flag_1', false);
             assert.equal(op.flags.set.length, 2);
             assert.equal(op.flags.set[0].state, false);
             done();
-            
+
         });
-        
+
         it('should invalidate a flag set on a flag remove', function(done) {
-           
+
             var op = new UpdateMap.MapOperation();
-            
+
             op.setFlag('flag_1', true);
             op.setFlag('flag_2', false);
             op.removeFlag('flag_2');
@@ -560,13 +560,13 @@ describe('UpdateMap', function() {
             assert.equal(op.flags.remove[0], 'flag_2');
             assert(op._hasRemoves());
             done();
-            
+
         });
-        
+
         it('should invalidate a remove flag on a set flag', function(done) {
-           
+
             var op = new UpdateMap.MapOperation();
-            
+
             op.removeFlag('flag_1');
             op.removeFlag('flag_2');
             assert.equal(op.flags.remove.length, 2);
@@ -576,45 +576,45 @@ describe('UpdateMap', function() {
             assert.equal(op.flags.set.length, 1);
             assert(op._hasRemoves());
             done();
-            
+
         });
-        
+
         it('should nest maps', function(done) {
-            
+
             var op = new UpdateMap.MapOperation();
             op.map('map_1')
                     .setFlag('some_flag', true)
                     .incrementCounter('counter_1', 5)
                     .removeRegister('register_1');
-            
+
             assert.equal(op.counters.increment.length, 0);
             assert.equal(op.flags.set.length, 0);
             assert.equal(op.registers.remove.length, 0);
             assert.equal(op.maps.modify.length, 1);
-            
+
             assert.equal(op.maps.modify[0].map.counters.increment.length, 1);
             assert.equal(op.maps.modify[0].map.flags.set.length, 1);
             assert.equal(op.maps.modify[0].map.registers.remove.length, 1);
             assert(op._hasRemoves());
             done();
-            
+
         });
-    
+
         it('should invalidate a map modify on a map remove', function(done) {
             var op = new UpdateMap.MapOperation();
             op.map('map_1').setFlag('some_flag', true);
-            
+
             op.removeMap('map_1');
             assert.equal(op.maps.modify.length, 0);
             assert.equal(op.maps.remove.length, 1);
             assert(op._hasRemoves());
             assert.equal(op.maps.remove[0], 'map_1');
             done();
-            
+
         });
-        
+
         it('should invalidate a map remove on a map modify', function(done) {
-            
+
             var op = new UpdateMap.MapOperation();
             op.removeMap('map_1');
             op.removeMap('map_2');
@@ -624,9 +624,9 @@ describe('UpdateMap', function() {
             assert.equal(op.maps.modify.length, 1);
             assert(op._hasRemoves());
             done();
-            
+
         });
-    
+
     });
 });
 
diff --git a/test/unit/fetchvalue.js b/test/unit/fetchvalue.js
index 84941f3..28e518d 100644
--- a/test/unit/fetchvalue.js
+++ b/test/unit/fetchvalue.js
@@ -24,6 +24,7 @@ var RpbErrorResp = require('../../lib/protobuf/riakprotobuf').getProtoFor('RpbEr
 var assert = require('assert');
 
 describe('FetchValue', function() {
+
     describe('Build', function() {
         it('should build a RpbGetReq correctly', function(done) {
             
@@ -149,4 +150,4 @@ describe('FetchValue', function() {
        });
        
     });
-});
\ No newline at end of file
+});