TikTok total_chunk_count rounds down: the final chunk can reach 128 MB
TikTok's Content Posting API sets total_chunk_count to video_size divided by chunk_size, rounded down, so the last chunk is bigger. Worked sizes and a checker.

total_chunk_count is video_size divided by chunk_size, rounded down, so the last chunk is never smaller than the others: it carries the remainder. TikTok's Media Transfer Guide (last updated August 4, 2026) says each chunk must be at least 5 MB and at most 64 MB, except the final chunk, which can be larger than chunk_size (up to 128 MB) to take trailing bytes.
A 150 MB file with 64 MB chunks therefore uploads as two chunks, 64 MB and 86 MB, not three. If you round up instead, TikTok's count will not match yours and the upload fails.
The rules in one table
These are the limits the guide states for chunked file upload. The guide writes sizes as MB without defining the unit, so the sample code uses 1,000,000 bytes and you should keep a margin.
| Rule | Value |
|---|---|
| Chunk size, normal chunks | 5 MB to 64 MB |
| Final chunk | May exceed chunk_size, up to 128 MB |
| Video under 5 MB | Upload whole; chunk_size equals the byte size |
| Video over 64 MB | Must use multiple chunks |
| Chunk count | 1 to 1000 |
| Order | Chunks must be uploaded sequentially |
Check your plan before you upload
This checker turns the rules into code. It refuses a 70 MB file at a 64 MB chunk size, because rounding down gives one chunk and the guide says a video over 64 MB needs multiple chunks; a smaller chunk_size such as 35 MB gives two.
import asyncio
MB = 1_000_000
def plan(size, chunk):
if size < 5 * MB:
return [size]
if not 5 * MB <= chunk <= 64 * MB:
raise ValueError("chunk must be 5-64 MB")
count = size // chunk
if not 1 <= count <= 1000:
raise ValueError("chunk count out of range")
if size > 64 * MB and count < 2:
raise ValueError("over 64 MB needs 2+ chunks")
sizes = [chunk] * (count - 1)
sizes.append(size - chunk * (count - 1))
if sizes[-1] > 128 * MB:
raise ValueError("final chunk over 128 MB")
return sizes
async def main():
for size in (4 * MB, 150 * MB, 200 * MB, 70 * MB):
try:
s = plan(size, 64 * MB)
print(size // MB, "MB:", len(s), "chunks, last", s[-1] // MB, "MB")
except ValueError as e:
print(size // MB, "MB:", e)
asyncio.run(main())Where the byte size comes from
After a Sume job finishes, for example a video trim result, the job returns a video_url for the new MP4. Read its byte length (a HEAD request is enough), pick chunk_size, and run the plan above. Each PUT to TikTok's upload_url carries a Content-Range: bytes first-last/total header, as in the guide's HTTP schema.
Steps
- Read the final MP4's byte length.
- Choose a chunk_size between 5 MB and 64 MB.
- Set total_chunk_count to the rounded-down quotient, and let the last chunk take the remainder.
- Send chunks in order with correct Content-Range headers.
- If the plan raises, change chunk_size, not the file.
Working notes
A common mistake is treating chunk_size as a request rather than a plan. TikTok reads chunk_size and total_chunk_count from your init call and expects the bytes you send to match them exactly. If the file is 150 MB and you declare three 64 MB chunks, the numbers cannot be satisfied, so compute both values from the byte length first and reuse them for every PUT. Log the planned sizes next to the job id so a failed upload can be retried at the right chunk.
Caveat
The guide is the source for these limits and it is dated; TikTok may change them. The Direct Post and Upload endpoints have their own reference pages, and those are where field names and responses live.
Sources
Related posts
More in Developers
- Track AI video spend per job: Synthesia Billing API vs Sume job cost
Synthesia added a Billing API and auto top-up. On Sume, every finished job reports usage.cost, so you can keep a per-job ledger without a billing endpoint.
- Transcribe a 30-minute file: OpenAI 25 MB cap vs Sume 10-minute jobs
A 30-minute file hits OpenAI's 25 MB upload limit and Sume's 10-minute duration hint. How to split once, transcribe in pieces, and re-base the word timings.
- Transcribe a 30-minute recording in three 600-second STT jobs: $0.33
Sume STT takes at most 600 seconds per job. Cut a 30-minute video into three 10-minute mp3 pieces with audio detach and transcribe each: $0.33 total.
- Transcribe a clip when you do not know the language: STT auto-detect
Omit language_code on Sume speech-to-text and the job auto-detects the language. What the result returns, the 10-minute cap, and the $0.01 a minute rate.
Written by Sume