# Troubleshooting

This page starts from a symptom (a failing build, a refused deployment, an API error) and leads to its real cause and its fix. It relies on the codes the platform returns: each names a cause, where to fix it and the next action.

## Where to read the cause

A failed deployment carries, in the console's **Déploiement** (Deployment) screen (and in **Première mise en ligne** (First go-live) for the first one), a « Pourquoi il a échoué » (why it failed) card. It always holds three lines:

- the **cause**, in one sentence, specific to the failure class;
- **Pour ce déploiement** (for this deployment), what the platform recorded about this particular failure when it says more: an exit code, a node state, a date;
- **Où** (where) to fix, then **À faire** (to do).

A last line says who fixes it: « le dépôt » (the repository: your code or configuration) or « la plateforme » (the platform: retry; if the failure persists, it does not come from you). When the fix happens in the console, a button leads there: « Ouvrir les variables » (open the variables), or « Corriger … dans les paramètres » (fix … in the settings). Text your repository wrote (the output of the failing command) shows separately, in its own frame: that is the repository speaking, not the platform.

From an agent, the details are read with `deployment_read` (fields `failureCatalog` and `failureReason`) and the log with `deployment_log_read`.

When the platform has not classified the failure, the card says so: read the build log, then redeploy. If the failure recurs identically, report it quoting the deployment identifier.

## Reading an API error

Every error from the API, the command line and the MCP tools has the same shape:

```json
{
  "code": "plafond_de_depense_atteint",
  "message": "…what to do, in one sentence…",
  "cause": { "fr": "…", "en": "…" },
  "champ": [],
  "suite": { "genre": "aucune", "raison": "…" }
}
```

- `code` is stable: branch your behaviour on it, never on the message.
- `champ` names the faulty fields, never the value received.
- `suite` gives the next call: a tool and its arguments (`outil`), the same request to retry, corrected or not (`reprendre`), or none, with its reason (`aucune`).

A 500 (`internal_error`) is logged: quote the request identifier from the details to support.

## A build fails

Start with the « Pourquoi il a échoué » card, then the log. The most frequent causes, in the order they occur:

1. **Fetching the code.** `fetch_failed`: most often a private GitHub repository the platform has no access to; install the GitHub application ticking this repository, then retry. `reference_introuvable`: the requested branch or commit does not exist.
2. **The repository's declaration.** `declaration_refusee`: `glowsoft.json` is invalid, or declares more services or tasks than the tier allows. `controles_refuses`: `.bastide/controles.yaml` is unreadable.
3. **Variables.** `variables_requises_manquantes`: the repository's `.env.example` declares variables missing from the environment. The simplest fix is « Importer un .env » in **Variables**.
4. **Detection.** `framework_not_detected`: nothing is recognised at the build root; provide a `Dockerfile` or fix the project's root directory.
5. **Dependencies.** `dependances_en_conflit`, `installation_des_dependances`, `build_verrou_desynchronise`: the manifest or lock file needs fixing, then versioning.
6. **Your code.** `script_de_construction`: a step of your build returned a non-zero code. `commande_introuvable` (exit 127): a tool it calls is not declared among the dependencies.
7. **Bounds.** `build_limite_duree`, `build_limite_memoire`, `build_limite_disque`, `build_limite_journal`, `build_limite_taille`: the build exceeded what the tier grants.

With your own `Dockerfile`, the platform refuses before building any instruction it does not serve, quoting the line: `# syntax=`, `VOLUME`, `ONBUILD`, remote `ADD`, a registry off the list, a privileged `RUN` option. See [Builds](builds.md).

## Production refuses a vulnerable image

After the build, the image is scanned. Two cases block promotion to production; preview environments deploy as before:

- `image_vulnerabilite_exploitee`: a vulnerability is in the catalogue of actively exploited vulnerabilities. No exemption lifts this refusal.
- `image_vulnerabilite_critique`: a vulnerability with a CVSS score of 9.0 or more, covered by no exemption in force.

Update the named package to its fixed version, most often by rebuilding on a more recent base image, then redeploy. The scan report and the inventory are attached to the image. An image variable shaped like a known secret also blocks production (`image_variable_de_secret`): revoke the value with its issuer first, since it is published in an image layer.

## No build starts any more

Two caps stop builds without ever touching online sites:

- `plafond_de_depense_atteint`: the organisation's spending has reached its cap for the cycle. Two authorised people raise it from **Facturation** (Billing), or the next cycle reopens builds.
- `quota_de_construction_atteint`: the project has used its build minutes for the month. They come back on the first of the next month (UTC); an upgrade increases them at once. For the free project, the code is `quota_gratuit_construction`.

See [Billing](billing.md) and [Limits per tier](limits.md).

## The deployment does not reach production

`controles_non_satisfaits`: required checks declared for production are not satisfied; the online version does not change. Read the deployment's check status (`deployment_list`), fix what fails, then redeploy. Only a person can override, with a reason that stays in the audit log; an agent receives `contournement_reserve`. See [Checks](checks.md).

## The application does not start, or does not answer

The build succeeded, but the workload does not become healthy:

- `sonde_sans_reponse`: the container runs, the application does not answer the probe in time. Check that it listens on `0.0.0.0` and on the port in the `PORT` variable. With your own `Dockerfile`, the port is 3000 unless `port` is declared in `glowsoft.json`; an `EXPOSE` is not enough. If the application starts slowly, declare `probe.startupBudgetSeconds`, and the probe path with `probe.path`.
- `redemarrage_en_boucle`: the application exits or crashes on start-up, at least three times. The last log lines attached to the deployment show the error: often a missing variable or an unreachable database.
- `memoire_depassee`: the kernel killed the workload at the tier's memory cap. The report gives the observed value and the limit.
- `release_sans_port`: the release was built without a recorded port; redeploy from the Git reference.

The file system is read-only, except `/tmp`: an application that writes elsewhere fails on start-up. See [Migrate from a VPS](from-vps.md) for the full runtime contract.

## The domain stays « pending »

A domain is only served once its proof has been read in DNS.

1. Check the records returned by `domain.add` (or **Domaines**): a TXT proof, then A and AAAA for an apex, or a CNAME for a subdomain.
2. The TXT token is valid for seven days. Calling `domain.add` again on a pending domain returns the same token and rereads DNS at once.
3. `domaine_deja_servi`: another project already serves this domain; remove it from that project first. `domaine_reserve`: the name is under a platform zone and cannot be attached. `projet_non_revendique`: a project created by an agent must be claimed by a person before receiving a domain.

See [Domains](domains.md).

## Too many requests: 429

`rate_limited`: the token has used up a rate limit over the elapsed window. Each token has 600 calls per minute, and 60 per minute for writes and secret reads. Wait the number of seconds in `Retry-After`, then resume; read `RateLimit-Remaining` to slow down before being refused. `trop_de_tentatives`: five sign-in failures within fifteen minutes; the wait doubles with each further failure. `plafond_de_creations_de_projet`: an agent created five projects within the rolling day.

## The 30 most useful codes

| Code | Status | Cause | What to do |
| --- | --- | --- | --- |
| `invalid_request` | 400 | A field is missing, malformed or contradictory | Fix the fields named in `champ`, then retry |
| `unauthenticated` | 401 | Token missing or invalid | Sign in again (`bastide login`) or mint a new token |
| `insufficient_rank` | 403 | Rank too low on this scope | Ask an administrator for the rank |
| `token_scope_missing` | 403 | The token lacks the required scope | Create a token that carries it |
| `agent_action_forbidden` | 403 | Action reserved to a person | Do it from the console or the API, under your account |
| `second_factor_required` | 403 | A second factor is required | Enrol an app or a passkey in **Compte** (Account) |
| `validation_humaine_requise` | 403 | An irreversible operation is validated by a person | Validate it from a personal account |
| `not_found` | 404 | Target not found or outside your scope | Take the identifier from a previous response |
| `conflict` | 409 | The request contradicts the current state | Reread the state, then retry |
| `confirmation_requise` | 428 | Irreversible operation, in two steps | Retry with the returned nonce (five minutes) |
| `nonce_expire` | 400 | The nonce is older than five minutes | Redo the first step |
| `rate_limited` | 429 | Rate limit reached | Wait for `Retry-After` |
| `internal_error` | 500 | Internal error, logged | Quote the request identifier to support |
| `timeout` | 503 | Time exceeded, no effect | Retry under the same idempotency key |
| `backend_indisponible` | 503 | The project's database is unreachable | Redeploy if the backend was not ready; otherwise, support |
| `quota_exceeded` | 409 | Variable (1,000) or byte cap reached | Delete or shrink variables |
| `plafond_de_depense_atteint` | 409 | Cycle spending cap reached | Raise it with two people, or wait for the cycle |
| `quota_de_construction_atteint` | 409 | Month's minutes used up | Wait for the 1st, or upgrade |
| `controles_non_satisfaits` | 409 | Required checks not satisfied | Fix, then redeploy |
| `rien_a_restaurer` | 409 | No previous release to restore | List with `deployment_restorable_list` |
| `domaine_deja_servi` | 409 | Domain served by another project | Remove it from the other project |
| `fetch_failed` | failure | Git could not fetch the code | Install the GitHub app on the repository, or fix the address |
| `declaration_refusee` | failure | `glowsoft.json` invalid or beyond the tier | Fix the file on the default branch |
| `variables_requises_manquantes` | failure | `.env.example` variables missing | « Importer un .env » in **Variables** |
| `framework_not_detected` | failure | Nothing recognised at the root | Provide a `Dockerfile`, or fix the project root |
| `script_de_construction` | failure | A build step failed | Read the command's output in the log |
| `image_vulnerabilite_critique` | failure | Critical vulnerability with no exemption | Update the named package, then redeploy |
| `sonde_sans_reponse` | failure | The application does not answer the probe | Listen on `0.0.0.0:$PORT`, declare `port` and `probe` |
| `redemarrage_en_boucle` | failure | The application crashes on start-up | Read the last log lines |
| `memoire_depassee` | failure | Tier memory cap exceeded | Reduce the footprint, or upgrade |

« failure » means a cause recorded on a failed deployment, not an HTTP response. The full list of API codes is published with each operation in the [API reference](../reference/en/api.md).

## Reporting a problem

If nothing here matches, write to support quoting the deployment identifier (`dep_…`) or the error's request identifier, and the code received. Never paste a secret's value.

See also: [Deploy](deploy.md), [Builds](builds.md), [Logs](logs.md), [Limits per tier](limits.md), [FAQ](faq.md).
