Why a deploy failed: 6 common causes and fixes
Almost every rejected deploy comes down to one of six causes, and in each case Tuqo tells you what exactly is wrong with your file set instead of a generic “index.html required”. Below are those six cases, what the error says and what to do. If the site did publish but behaves wrongly, that is a different story: see what AI agents break in sites.
A note on language. The messages below are quoted in English. Errors in the panel and
the REST API come in the language of the request: English in the English panel or with
Accept-Language: en, Russian otherwise. Over MCP they are always in English.
Build errors and build logs follow the language of the site owner’s account, set in
Profile settings under Email and notification language.
1. Nested folder: index.html is not at the root
The most common case in production. Someone packed the whole folder, so everything sits
one level deeper: my-site/index.html instead of index.html.
One extra level in an archive is fine. If a tar.gz or zip has exactly one
top-level folder, Tuqo steps into it and publishes its contents. An archive made with
tar czf site.tar.gz my-site publishes as is.
The error appears when there are two levels, my-site/dist/index.html, and the middle
folder holds nothing else:
The site files are in the nested folder “dist”, but they must be at the root. Pack the CONTENTS of the folder, not the folder itself:
tar -czf site.tar.gz -C ./dist .— or just drag the folder into the panel, which handles this automatically.
Files sent one by one are not flattened. That is how agents publish over MCP, REST and
the CLI: paths go as they are, and my-site/index.html does not become the home page:
all files are inside the nested folder “my-site”, but index.html must be in the root. Drag the “my-site” folder itself (its contents become the root) or remove the extra folder level.
If there are several top-level folders and the root has neither index.html nor
package.json, Tuqo lists what actually arrived. One look at the list shows that the
wrong thing was packed.
2. index.htm instead of index.html
A site opens at /, and that address serves exactly index.html. A file with another name
or in another letter case will not become the home page:
the home page must be named exactly index.html, but the set has “index.htm”. Rename the file and upload again.
If the root has other HTML pages but no home page, the message says that too: it lists the
pages it found (about.html, contact.html) and reminds you that the site opens with
index.html. Rename your home page.
3. One file gzipped instead of a folder archive
gzip index.html produces index.html.gz. Its magic bytes say gzip, so the upload check
lets it through, but there is no tar structure inside:
Could not unpack the archive: there is no tar structure inside. It looks like a single file was compressed instead of a folder. Build the archive from the CONTENTS of the site folder:
tar -czf site.tar.gz -C ./folder .— or just drag the folder into the panel. A .zip works too.
Two formats are accepted: tar.gz and zip. Anything else is rejected right away with
“Archive not recognized: tar.gz and zip are accepted.” Zip is the safer choice, by the way:
Windows and most AI tools produce it by default.
4. The build produced nothing
If the archive root has a package.json, Tuqo treats the upload as a build project and
builds it on Node 20: npm ci when there is a lock file (otherwise npm install), then
npm run build. Two typical failures:
-
package.jsonhas nobuildscript. The build fails onnpm run build, and the log shows npm’s missing script error. Add the script. For a repository connected with Git CD, you can also set your own build command in the Git CD settings. -
The output is not where Tuqo looks for it.
The build succeeded, but no folder with the finished site was found. We look for dist, build, out, _site, public, site, .vitepress/dist, .output/public, storybook-static. If your stack puts the output elsewhere, set the output directory in the Git CD settings or upload the built folder.
The reverse case: you publish a built site as files, and a package.json slipped into
the set. Then you get “package.json found in the root: this is a build project. For static
files remove it; to build, use deploy_site (an archive with the sources)”.
In the panel, the site’s Deploys tab shows the failed deploy with its status and the error text from the end of the build log.
5. You hit a limit
Each publishing path has its own ceiling:
- A folder dropped into the panel: up to 2000 files and about 36 MB. The panel tells you
the total size and suggests packing a tar.gz or zip (up to 50 MB) or using the CLI,
npx @tuqo/cli deploy. - An archive in the panel, over REST or with MCP
deploy_site: 50 MB. A bigger one is rejected: the panel and the REST API say “The source archive exceeds 50 MB.”, and MCP returns the same message. - The CLI: up to 2000 files, up to 50 MB per file, in total within your plan’s storage. There is no request body size limit: files go up one by one.
A separate common story is “too many files”: node_modules or the source folder ended up in
the archive. Publish the build output, not the whole project. Heavy sites with photos go
through the CLI; see the guide on
updating a media-heavy site without re-uploads.
6. Service files and __tuqo/
Some paths are never published, and that is not an error: they are simply dropped from the
set. These are .git, .hg, .svn, .bzr, .env (and .env.local, .env.production),
.ssh, .aws, .gnupg, .docker, .kube, .config, .netrc, .npmrc, .pypirc,
.htpasswd, .htaccess, .DS_Store. Every segment of the path is checked, case-insensitively,
so frontend/.env.local is dropped as well.
The __tuqo/ prefix is separate: the platform reserves it for its own pages (the password
login screen, file delivery). A site file under that path would never be served, so it is
not published at all.
If nothing but service files is left in the set, you will see the missing index.html
error. Agents get the list of dropped files in the skipped_paths field; there is no need
to send those files again.
FAQ
How do I build the archive correctly?
tar -czf site.tar.gz -C ./dist . — the dot at the end means “the contents of the folder”.
Or run zip -r site.zip . from inside the site folder. To check, run
tar -tzf site.tar.gz | head: the list should show ./index.html, not dist/index.html.
The deploy succeeded, but the site returns 404
Then index.html did not end up at the root of the published files, or the site is turned
off in its settings. A 404 on page refresh in an SPA with client-side routing is a different
problem with its own fix; see SPA 404 on refresh.
Where can I see why a build failed?
The site’s Deploys tab → the failed deploy: its status and the error text (the
last lines of the log). Over MCP, get_logs(deploy_id) returns the same.
Can I roll back if a new version breaks?
Yes, if your plan keeps more than one version: the Deploys tab → “Roll back to this”. Details are in the guide on rolling back to a previous version.