task: metadata: install: pip install -e .[test]
patch: diff --git a/mapbox/services/uploads.py b/mapbox/services/uploads.py
index b085cd5..86d49d4 100644
--- a/mapbox/services/uploads.py
+++ b/mapbox/services/uploads.py
@@ -2,6 +2,7 @@ from boto3.session import Session as boto3_session
 from uritemplate import URITemplate
 
 from mapbox.errors import InvalidFileError
+from mapbox.errors import ValidationError
 from mapbox.services.base import Service
 
 
@@ -45,6 +46,16 @@ class Uploader(Service):
                 429: "Too many requests"})
         return resp
 
+    def _validate_tileset(self, tileset):
+        """Validate the tileset name and
+        ensure that it includes the username
+        """
+        if '.' not in tileset:
+            tileset = "{0}.{1}".format(self.username, tileset)
+        if len(tileset) > 64:
+            raise ValidationError('tileset including username must be < 64 char')
+        return tileset
+
     def stage(self, fileobj, creds=None, callback=None):
         """Stages the user's file on S3
         If creds are not provided, temporary credientials will be generated
@@ -88,9 +99,7 @@ class Uploader(Service):
         Returns a response object where the json() contents are
         an upload dict
         """
-        if '.' not in tileset:
-            tileset = "{0}.{1}".format(self.username, tileset)
-
+        tileset = self._validate_tileset(tileset)
         account, _name = tileset.split(".")
 
         msg = {'tileset': tileset,
@@ -166,5 +175,6 @@ class Uploader(Service):
         Effectively replicates the upload functionality using the HTML form
         Returns a response object where the json() is a dict with upload metadata
         """
+        tileset = self._validate_tileset(tileset)
         url = self.stage(fileobj, callback=callback)
         return self.create(url, tileset, name=name, patch=patch)

problem_statement: Raise exception for too-long tileset names
Uploads API limits tileset names to 64 characters. Let's raise an exception before making an API call that will fail.

cc: @geografa 
repo: mapbox/mapbox-sdk-py
test_cmd: pytest --no-header -rA --tb=line --color=no -p no:cacheprovider -W ignore::DeprecationWarning
test_patch: diff --git a/tests/test_upload.py b/tests/test_upload.py
index 0111948..3bdbf99 100644
--- a/tests/test_upload.py
+++ b/tests/test_upload.py
@@ -385,3 +385,26 @@ def test_upload_patch(monkeypatch):
     assert res.status_code == 201
     job = res.json()
     assert job['tileset'] == "{0}.test1".format(username)
+
+
+def test_upload_tileset_validation():
+    with pytest.raises(mapbox.errors.ValidationError):
+        with open('tests/moors.json', 'rb') as src:
+            mapbox.Uploader(access_token=access_token).upload(
+                src, 'a' * 65, name='test1', patch=True)
+
+
+def test_upload_tileset_validation_username():
+    # even with 60 chars, the addition of the
+    # testuser username puts it over 64 chars
+    with pytest.raises(mapbox.errors.ValidationError):
+        with open('tests/moors.json', 'rb') as src:
+            mapbox.Uploader(access_token=access_token).upload(
+                src, 'a' * 60, name='test1', patch=True)
+
+
+def test_create_tileset_validation():
+    # even with 60 chars, the addition of the username puts it over 64 chars
+    with pytest.raises(mapbox.errors.ValidationError):
+        mapbox.Uploader(access_token=access_token).create(
+            'http://example.com/test.json', 'a' * 60)