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)

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 
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)

pip install -e .[test]
parse_log_pytest
requirements.txt
3.6
pytest --no-header -rA --tb=line --color=no -p no:cacheprovider -W ignore::DeprecationWarning
attrs==22.2.0
boto3==1.23.10
botocore==1.26.10
CacheControl==0.12.14
certifi==2021.5.30
charset-normalizer==2.0.12
click==8.0.4
click-plugins==1.1.1
cligj==0.7.2
coverage==6.2
coveralls==3.3.1
distlib==0.3.9
docopt==0.6.2
filelock==3.4.1
idna==3.10
importlib-metadata==4.8.3
importlib-resources==5.4.0
iniconfig==1.1.1
iso3166==2.1.1
jmespath==0.10.0
-e git+https://github.com/mapbox/mapbox-sdk-py.git@d503098e549834471e0857adf5163085af6b4355#egg=mapbox
msgpack==1.0.5
packaging==21.3
platformdirs==2.4.0
pluggy==1.0.0
polyline==1.4.0
py==1.11.0
pyparsing==3.1.4
pytest==7.0.1
pytest-cov==4.0.0
python-dateutil==2.9.0.post0
requests==2.27.1
responses==0.17.0
s3transfer==0.5.2
six==1.17.0
toml==0.10.2
tomli==1.2.3
tox==3.28.0
typing_extensions==4.1.1
uritemplate==4.1.1
urllib3==1.26.20
virtualenv==20.17.1
zipp==3.6.0

name: mapbox-sdk-py
channels:
  - defaults
  - https://repo.anaconda.com/pkgs/main
  - https://repo.anaconda.com/pkgs/r
  - conda-forge
dependencies:
  - _libgcc_mutex=0.1=main
  - _openmp_mutex=5.1=1_gnu
  - ca-certificates=2025.2.25=h06a4308_0
  - certifi=2021.5.30=py36h06a4308_0
  - ld_impl_linux-64=2.40=h12ee557_0
  - libffi=3.3=he6710b0_2
  - libgcc-ng=11.2.0=h1234567_1
  - libgomp=11.2.0=h1234567_1
  - libstdcxx-ng=11.2.0=h1234567_1
  - ncurses=6.4=h6a678d5_0
  - openssl=1.1.1w=h7f8727e_0
  - pip=21.2.2=py36h06a4308_0
  - python=3.6.13=h12debd9_1
  - readline=8.2=h5eee18b_0
  - setuptools=58.0.4=py36h06a4308_0
  - sqlite=3.45.3=h5eee18b_0
  - tk=8.6.14=h39e8969_0
  - wheel=0.37.1=pyhd3eb1b0_0
  - xz=5.6.4=h5eee18b_1
  - zlib=1.2.13=h5eee18b_1
  - pip:
      - attrs==22.2.0
      - boto3==1.23.10
      - botocore==1.26.10
      - cachecontrol==0.12.14
      - charset-normalizer==2.0.12
      - click==8.0.4
      - click-plugins==1.1.1
      - cligj==0.7.2
      - coverage==6.2
      - coveralls==3.3.1
      - distlib==0.3.9
      - docopt==0.6.2
      - filelock==3.4.1
      - idna==3.10
      - importlib-metadata==4.8.3
      - importlib-resources==5.4.0
      - iniconfig==1.1.1
      - iso3166==2.1.1
      - jmespath==0.10.0
      - msgpack==1.0.5
      - packaging==21.3
      - platformdirs==2.4.0
      - pluggy==1.0.0
      - polyline==1.4.0
      - py==1.11.0
      - pyparsing==3.1.4
      - pytest==7.0.1
      - pytest-cov==4.0.0
      - python-dateutil==2.9.0.post0
      - requests==2.27.1
      - responses==0.17.0
      - s3transfer==0.5.2
      - six==1.17.0
      - toml==0.10.2
      - tomli==1.2.3
      - tox==3.28.0
      - typing-extensions==4.1.1
      - uritemplate==4.1.1
      - urllib3==1.26.20
      - virtualenv==20.17.1
      - zipp==3.6.0
prefix: /opt/conda/envs/mapbox-sdk-py

tests/test_upload.py::test_create_tileset_validation
tests/test_upload.py::test_get_credentials tests/test_upload.py::test_create tests/test_upload.py::test_create_name tests/test_upload.py::test_list tests/test_upload.py::test_status tests/test_upload.py::test_delete tests/test_upload.py::test_stage tests/test_upload.py::test_big_stage tests/test_upload.py::test_upload tests/test_upload.py::test_upload_error tests/test_upload.py::test_invalid_fileobj tests/test_upload.py::test_upload_patch tests/test_upload.py::test_upload_tileset_validation tests/test_upload.py::test_upload_tileset_validation_username
mapbox/services/uploads.py
mapbox/services/uploads.py