> ## Documentation Index
> Fetch the complete documentation index at: https://docs.squarecloud.app/llms.txt
> Use this file to discover all available pages before exploring further.

# Fehler

> Behandle *APIError im Go SDK: Status, Code und Nachricht, errors.As und errors.Is, die eigenen Codes des SDK, die Code-Konstanten, Wiederholungen, Timeouts und Rate Limits.

Jeder API-, Netzwerk- und lokale Fehler hat einen einzigen Typ: `*squarecloud.APIError`. Untersuche ihn mit `errors.As`.

```go theme={"system"}
package main

import (
	"context"
	"errors"
	"fmt"
	"os"

	"github.com/squarecloudofc/sdk-api-go/v3"
)

func main() {
	ctx := context.Background()
	c := squarecloud.New(os.Getenv("SQUARECLOUD_API_KEY"))
	appID := "abc123def456abc123def456"

	err := c.Apps.Start(ctx, appID)

	var apiErr *squarecloud.APIError
	if errors.As(err, &apiErr) {
		fmt.Println(apiErr.Status, apiErr.Code, apiErr.Message)
		fmt.Println(apiErr.Method, apiErr.Path) // "POST" "/v2/apps/<id>/start"
	}
}
```

## `APIError`

| Feld      | Typ      | Beschreibung                                                                                                                               |
| --------- | -------- | ------------------------------------------------------------------------------------------------------------------------------------------ |
| `Status`  | `int`    | HTTP-Status. `0`, wenn keine Antwort eingetroffen ist (Netzwerkfehler, Timeout, lokale Prüfung)                                            |
| `Code`    | `string` | Der Fehlercode der API, z. B. `APP_NOT_FOUND`, oder einer der Codes des SDK. Vergleiche ihn mit den [`Code*`-Konstanten](#code-konstanten) |
| `Message` | `string` | Die Erklärung des Servers. `""`, wenn der Server nur einen Code gesendet hat                                                               |
| `Method`  | `string` | HTTP-Methode des fehlgeschlagenen Aufrufs                                                                                                  |
| `Path`    | `string` | URL-Pfad des fehlgeschlagenen Aufrufs, ohne den Query-String                                                                               |

`Unwrap()` gibt die Ursache zurück (den Transport-, Dekodier- oder Kontextfehler) bei `NETWORK_ERROR`, `TIMEOUT` und ungültigem JSON, sonst `nil`. `Error()` erzeugt `squarecloud: <METHOD> <path>: HTTP <status> <CODE>: <message>`, ohne `HTTP <status>`, wenn der Status `0` ist, und ohne `: <message>`, wenn die Nachricht leer ist. Prüfe die Felder, nicht diesen Text.

### Abgebrochene und abgelaufene Kontexte

Ein Aufruf, dessen `ctx` abgebrochen wird, gibt einen `*APIError` mit `NETWORK_ERROR` zurück, und einer, dessen Deadline abläuft, gibt `TIMEOUT` zurück, beide mit Status `0`. Sie lassen sich zum Fehler des Kontexts entpacken:

```go theme={"system"}
_, err := c.Apps.Get(ctx, appID)

switch {
case errors.Is(err, context.Canceled):
	// you canceled ctx
case errors.Is(err, context.DeadlineExceeded):
	// the deadline of ctx, or the default one, passed
}
```

Einige Fehler sind kein `*APIError`:

* [`Realtime.Next`](/de/sdks/go/realtime#den-stream-beenden) gibt das reine `ctx.Err()` zurück, wenn sein `ctx` endet, und `io.EOF`, wenn der Stream normal endet.
* Probleme auf Seite des Aufrufers sind einfache Fehler: ein `nil`-Upload-Reader, eine Snapshot-URL oder Basis-URL, die sich nicht parsen lässt, eine Eingabe, die `encoding/json` nicht kodieren kann, und ein Fehler des an `DownloadSnapshot` übergebenen `io.Writer`.

## Codes des SDK

| Status   | Code              | Konstante           | Wann                                                                                                                                                                                                               |
| -------- | ----------------- | ------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| 0        | `NETWORK_ERROR`   | `CodeNetworkError`  | Keine Antwort (DNS, Verbindung zurückgesetzt, Body abgeschnitten), oder `ctx` abgebrochen. Der ursprüngliche Fehler steht in `Unwrap()`                                                                            |
| 0        | `TIMEOUT`         | `CodeTimeout`       | Keine Antwort vor Ablauf der Deadline (siehe [Timeouts](/de/sdks/go/client#timeouts))                                                                                                                              |
| 0        | `FILE_TOO_LARGE`  | `CodeFileTooLarge`  | Lokale Prüfung: ein Upload über 100 MB oder ein `Files.Write` über 10 MB. Es wurde nichts gesendet                                                                                                                 |
| 0        | `INVALID_ID`      | `CodeInvalidID`     | Lokale Prüfung: eine ID, die leer, `.` oder `..` ist. Es wurde nichts gesendet                                                                                                                                     |
| 0        | `INVALID_API_KEY` | `CodeInvalidAPIKey` | Lokale Prüfung: Der Client wurde mit einem leeren Schlüssel erstellt. Jeder Aufruf außer `Service.Status`. Nur im Go SDK                                                                                           |
| beliebig | `UNKNOWN_ERROR`   | `CodeUnknown`       | Eine Antwort ohne Code (etwa die Fehlerseite eines Proxys), mit dem echten `Status` und der Nachricht `HTTP <status>`. Ein 2xx-Body, der kein JSON ist, hat die Nachricht `Invalid JSON in HTTP <status> response` |

## `Code*`-Konstanten

`Code` ist ein einfacher `string`. Das Paket hat eine Konstante pro öffentlichem API-Code, benannt nach ihm im Go-Stil (`CodeAppNotFound` für `APP_NOT_FOUND`, `CodeInvalidID`, `CodeDNSFailed`, ...), dazu die oben genannten eigenen Codes des SDK.

Die Liste der API-Codes wächst. **Behandle einen unbekannten Code anhand seines HTTP-Status**:

```go theme={"system"}
func handle(err error) error {
	var apiErr *squarecloud.APIError
	if !errors.As(err, &apiErr) {
		return err
	}

	switch apiErr.Code {
	case squarecloud.CodeAppNotFound:
		return nil
	case squarecloud.CodeContainerAlreadyStarted:
		return nil // fine
	}
	switch {
	case apiErr.Status == 429:
		return retryLater()
	case apiErr.Status >= 500:
		return reportOutage(apiErr)
	}
	return err
}
```

## Fehler bei jedem Aufruf

| Status | Code                    | Wann                                                                                                                              |
| ------ | ----------------------- | --------------------------------------------------------------------------------------------------------------------------------- |
| 401    | `ACCESS_DENIED`         | Fehlender, unbekannter, widerrufener oder abgelaufener API-Schlüssel                                                              |
| 403    | `MISSING_SCOPE`         | Dem Schlüssel fehlt der Scope dieses Aufrufs. `Message` nennt ihn                                                                 |
| 403    | `RESOURCE_NOT_ALLOWED`  | Der Schlüssel ist auf andere Apps oder Datenbanken beschränkt                                                                     |
| 403    | `PERMISSION_DENIED`     | Deine Workspace-Rolle erlaubt die Aktion nicht                                                                                    |
| 404    | `ROUTE_NOT_FOUND`       | Unbekannte Route                                                                                                                  |
| 429    | `RATE_LIMITED`          | Sperre von Konto, Schlüssel oder IP (kann etwa 30 Min. dauern) sowie das Limit der Netzwerk-Endpoints und von `Account.Snapshots` |
| 429    | `KEEP_CALM`             | Zu schnell für diese Route                                                                                                        |
| 500    | `INTERNAL_SERVER_ERROR` | Serverfehler                                                                                                                      |
| 503    | `DATABASE_UNAVAILABLE`  | Die Datenbank der Plattform ist nicht verfügbar. Eine Mutation wurde möglicherweise bereits angewendet                            |

## API-Codes nach Gruppen

<AccordionGroup>
  <Accordion title="Nicht gefunden">
    `APP_NOT_FOUND`, `DATABASE_NOT_FOUND`, `WORKSPACE_NOT_FOUND`, `MEMBER_NOT_FOUND`, `FILE_NOT_FOUND`, `SNAPSHOT_NOT_FOUND`, `REPOSITORY_NOT_FOUND`, `BRANCH_NOT_FOUND`, `ROUTE_NOT_FOUND`
  </Accordion>

  <Accordion title="Validierung">
    `INVALID_ACCESS_TOKEN`, `INVALID_AUTORESTART`, `INVALID_BRANCH_LENGTH`, `INVALID_CODE`, `INVALID_CONTENT`, `INVALID_CONTENT_TYPE`, `INVALID_DATABASE_TYPE`, `INVALID_DATABASE_VERSION`, `INVALID_DESCRIPTION`, `INVALID_DISPLAY_NAME`, `INVALID_DOMAIN`, `INVALID_ENCODING`, `INVALID_ENV_CONTENT`, `INVALID_FILE`, `INVALID_FILENAME`, `INVALID_FILTER`, `INVALID_GROUP`, `INVALID_ID`, `INVALID_INPUT`, `INVALID_JSON_BODY`, `INVALID_MEMORY`, `INVALID_NAME`, `INVALID_PARAMETERS`, `INVALID_PATH`, `INVALID_RESET_TYPE`, `INVALID_SCOPE`, `INVALID_SNAPSHOT_ID`, `INVALID_SUBDOMAIN`, `INVALID_TIME_RANGE`, `INVALID_VERSION_ID`, `MISSING_PARAMETERS`, `MISSING_REQUIRED_FIELDS`, `NO_UPDATE_DATA`, `VALIDATION_FAILED`, `VALIDATION_TIMEOUT`, `ENV_NAME_TOO_LONG`, `ENV_CONTENT_TOO_LONG`, `TOO_MANY_ENV_VARS`, `RESERVED_DOMAIN`, `CANNOT_SET_SUBDOMAIN`, `STATIC_APP_ENV_NOT_SUPPORTED`
  </Accordion>

  <Accordion title="Authentifizierung und Berechtigungen">
    `ACCESS_DENIED`, `MISSING_SCOPE`, `RESOURCE_NOT_ALLOWED`, `PERMISSION_DENIED`, `SCOPE_NOT_GRANTABLE`, `BLOCKED_PATH`, `UPGRADE_REQUIRED`
  </Accordion>

  <Accordion title="Limits und Rate Limits">
    `RATE_LIMITED`, `KEEP_CALM`, `APPLICATIONS_LIMIT_REACHED`, `WORKSPACE_LIMIT_REACHED`, `MEMBERS_LIMIT_REACHED`, `LOAD_BALANCER_LIMIT_REACHED`, `DAILY_SNAPSHOTS_LIMIT_REACHED`, `INSUFFICIENT_MEMORY`, `FILE_TOO_LARGE`, `PAYLOAD_TOO_LARGE`, `REALTIME_MAX_CONNECTIONS`, `REALTIME_MAX_CONNECTIONS_APP`, `AI_DAILY_LIMIT_REACHED`, `AI_MAX_CONCURRENT_STREAMS`, `AI_NO_PLAN_LIMIT_REACHED`
  </Accordion>

  <Accordion title="Container (Starten, Stoppen, Neustarten)">
    `CONTAINER_ALREADY_STARTED`, `CONTAINER_ALREADY_STOPPED`, `CONTAINER_TEMPORARILY_SUSPENDED`, `CONTAINER_NOT_FOUND`, `CONTAINER_INSUFFICIENT_DISK_SPACE`, `CONTAINER_NETWORK_CONFLICT`, `ACTION_FAILED`, `DATABASE_NOT_RUNNING`
  </Accordion>

  <Accordion title="Uploads, Dateien und Commits">
    `UPLOAD_BUSY`, `UPLOAD_FAILED`, `UPLOAD_ABORTED`, `STORAGE_UPLOAD_FAILED`, `COMMIT_FAILED`, `READ_FAILED`, `SAVE_FAILED`, `RENAME_FAILED`, `DELETE_FAILED`, `REQUEST_ABORTED`, `EMPTY_RESPONSE`
  </Accordion>

  <Accordion title="Snapshots">
    `SNAPSHOT_FAILED`, `SNAPSHOT_PROCESSING`, `SNAPSHOT_RESTORE_FAILED`, `SNAPSHOT_DATABASE_MISMATCH`, `RESTORE_IN_PROGRESS`
  </Accordion>

  <Accordion title="Deploys und GitHub">
    `GIT_ALREADY_CONFIGURED`, `GIT_NOT_CONFIGURED`, `GITHUB_NOT_CONNECTED`, `REPOSITORY_BRANCH_ALREADY_CONFIGURED`, `REPOSITORY_NOT_AVAILABLE`, `REPOSITORY_PERMISSION_REQUIRED`, `FAILED_TO_FETCH`
  </Accordion>

  <Accordion title="Netzwerk und Domains">
    `ANALYTICS_BUSY`, `UNABLE_TO_FETCH_ANALYTICS`, `UNABLE_TO_FETCH_ERRORS`, `UNABLE_TO_FETCH_PERFORMANCE`, `DNS_FAILED`, `DOMAIN_ALREADY_EXISTS`, `NO_CUSTOM_DOMAIN`, `PURGE_CACHE_FAILED`, `LOGS_UNAVAILABLE`, `METRICS_NOT_SUPPORTED`
  </Accordion>

  <Accordion title="Datenbanken und Workspaces">
    `DATABASE_CREATION_FAILED`, `DATABASE_UNAVAILABLE`, `RESET_FAILED`, `WORKSPACE_CREATION_FAILED`, `APP_ALREADY_IN_WORKSPACE`, `MEMBER_ALREADY_ADDED`, `CANNOT_EDIT_OWNER`, `CANNOT_INVITE_OWNER`, `CANNOT_LEAVE_OWNER`, `CONFLICTING_RESOURCES`
  </Accordion>

  <Accordion title="Plattform">
    `INTERNAL_SERVER_ERROR`, `CLUSTER_MAINTENANCE_TRY_LATER`, `CLUSTER_SELECTION_FAILED`, `CLUSTER_TIMEOUT`, `CLUSTER_UNAVAILABLE`, `AI_UNAVAILABLE`
  </Accordion>

  <Accordion title="Veraltet">
    `CodeRateLimit` (`RATE_LIMIT`) und `CodeRateLimitExceeded` (`RATE_LIMIT_EXCEEDED`) werden weiterhin exportiert und sind als veraltet markiert: Die API antwortet jetzt in beiden Fällen mit `RATE_LIMITED` (`CodeRateLimited`).
  </Accordion>
</AccordionGroup>

Fehler von `AI.Chat` verwenden stattdessen kleingeschriebene OpenAI-Codes (`access_denied`, `rate_limit_exceeded`, `server_overloaded`, ...), die `Code` unverändert enthält. Siehe [KI](/de/sdks/go/ai#fehler).

## Wiederholungen

Das SDK wiederholt nur, was sich gefahrlos wiederholen lässt, bis zu `WithMaxRetries` Mal (Standard `2`, also bis zu 3 Versuche):

| Wiederholt                 | Methoden                                                                             |
| -------------------------- | ------------------------------------------------------------------------------------ |
| `NETWORK_ERROR`            | Nur `GET` (einschließlich Realtime-Öffnungen und `DownloadSnapshot` vor der Antwort) |
| 503 `UPLOAD_BUSY`          | Jede Methode                                                                         |
| 503 `ANALYTICS_BUSY`       | Jede Methode                                                                         |
| 503 `DATABASE_UNAVAILABLE` | Nur `GET`                                                                            |

**Nie** wiederholt werden:

* `TIMEOUT`;
* jedes **429**: `RATE_LIMITED` kann eine Sperre von etwa 30 Minuten sein, und auch `KEEP_CALM` wird nicht wiederholt;
* andere 5xx;
* KI-Fehler.

503 `DATABASE_UNAVAILABLE` kann eintreffen, nachdem eine Mutation bereits angewendet wurde, daher wiederholt das SDK ihn außerhalb von `GET` nicht. Wiederhole deine eigenen idempotenten Mutationen, wenn nötig. Ein Upload wird nur wiederholt, wenn sein Body erneut abgespielt werden kann: ein `io.ReaderAt` mit bekannter Größe, etwa eine `*os.File` (siehe [Commit und Upload](/de/sdks/go/commit_and_upload#akzeptierte-eingaben)).

Die Wartezeit vor Wiederholung `n` (ab 0) beträgt `min(8 s, 500 ms · 2^n) · U(0.5, 1)`: exponentielles Backoff mit 50 % bis 100 % Jitter. Setze `WithMaxRetries(0)`, um Wiederholungen abzuschalten.

## Timeouts

`WithTimeout` (30 s) gilt nur, wenn `ctx` keine Deadline hat, und eine Deadline deckt den gesamten Aufruf ab, einschließlich Wiederholungen und Backoff-Wartezeiten. Unter [Timeouts](/de/sdks/go/client#timeouts) findest du die Aufrufe mit einem Mindestwert von 2 Minuten und die Aufrufe ohne Standard-Deadline. Eine abgelaufene Deadline gibt `TIMEOUT` mit Status `0` zurück, wird nie wiederholt und lässt sich zu `context.DeadlineExceeded` entpacken.

## Rate Limits

Jedes Konto hat ein Limit an Anfragen pro 60 Sekunden, das sein Plan festlegt ([Werte](/de/api-reference/limitations-and-restrictions)), und manche Routen haben ein eigenes:

* **429 `RATE_LIMITED`**: eine Sperre des Kontos, API-Schlüssels oder der IP, die etwa 30 Minuten dauern kann. Auch das Limit der Netzwerk-Endpoints und von `Account.Snapshots`.
* **429 `KEEP_CALM`**: zu viele Aufrufe an eine Route in kurzer Zeit.

Das SDK wiederholt ein 429 nie. Werde langsamer und warte, bevor du es erneut versuchst.
