tuqo

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.json has no build script. The build fails on npm 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.

Documentation → · Publish checks →