{"record":{"id":"d621933b3b87bbac","repo":"nextcloud/all-in-one","slug":"your-desec-account-has-reached-its-domain-limit-an","errorCode":null,"errorMessage":"Your deSEC account has reached its domain limit and \"{domain}\" is not one of your existing domains. Remove an unused domain at desec.io, or contact deSEC support to raise the limit, then try again.","messagePattern":"Your deSEC account has reached its domain limit and \"(.+?)\" is not one of your existing domains\\. Remove an unused domain at desec\\.io, or contact deSEC support to raise the limit, then try again\\.","errorType":"exception","errorClass":"\\Exception","httpStatus":422,"severity":"error","filePath":"php/src/Desec/DesecManager.php","lineNumber":314,"sourceCode":"            } catch (TransferException $e) {\n                throw new \\Exception('Could not reach the deSEC API: ' . $e->getMessage());\n            }\n\n            $code = $res->getStatusCode();\n\n            if ($code === 201) {\n                return $domain;\n            }\n\n            // For a user-specified slug, the name may be unavailable (400/409) or the account's\n            // domain limit may be reached (403) precisely because the user already owns this\n            // domain. Reuse it rather than failing.\n            if (!$random && ($code === 400 || $code === 403 || $code === 409)) {\n                if ($this->ownsDomain($token, $domain)) {\n                    return $domain;\n                }\n                if ($code === 403) {\n                    throw new \\Exception(\n                        'Your deSEC account has reached its domain limit and \"' . $domain . '\" is not '\n                        . 'one of your existing domains. Remove an unused domain at desec.io, or contact '\n                        . 'deSEC support to raise the limit, then try again.'\n                    );\n                }\n                throw new \\Exception('\"' . $domain . '\" is already taken. Please choose a different subdomain and try again.');\n            }\n\n            if ($code === 409) {\n                // Random slug collided with an existing name — try another.\n                continue;\n            }\n\n            throw new \\Exception('Unexpected response from deSEC during domain registration (HTTP ' . $code . '): ' . $res->getBody()->getContents());\n        }\n\n        throw new \\Exception('Could not register a free dedyn.io domain after ' . self::MAX_SLUG_ATTEMPTS . ' attempts. Please try again.');\n    }","sourceCodeStart":296,"sourceCodeEnd":332,"githubUrl":"https://github.com/nextcloud/all-in-one/blob/6b788eec5e61733cf03ed380a3572e43ae3f11ce/php/src/Desec/DesecManager.php#L296-L332","documentation":"POST /domains/ returned 403 — the deSEC account is at its domain quota — and the follow-up ownership check (GET /domains/{name}/ returning 404) confirmed the requested domain is NOT already owned by this account, so it cannot be reused as the 400/409 recovery path would allow.","triggerScenarios":"User-specified slug, POST /domains/ → 403 (limit reached), then ownsDomain() → 404 (not yours): the quota is exhausted and this exact domain is unavailable for reuse.","commonSituations":"User registered several dedyn.io domains in earlier attempts and hit the free-account cap; default deSEC domain limit reached before finishing AIO setup.","solutions":["Log in at desec.io and delete an unused domain from the account, then retry","Contact deSEC support to raise the domain limit","Reuse a slug you already own — the code detects and reuses owned domains automatically","Use a fresh deSEC account/email if registering a separate instance is acceptable"],"exampleFix":"// before: create blindly and rely on the 403 error\n$manager->registerDomain($token, $slug);\n// after: check the account's domain list first and surface quota early\n$owned = json_decode($guzzle->get(\"$apiBase/domains/\", ['headers' => ['Authorization' => \"Token $token\"]])->getBody(), true);\nif (count($owned) >= $domainLimit) {\n    throw new \\Exception('Domain limit reached: delete one domain at desec.io before continuing.');\n}\n$manager->registerDomain($token, $slug);","handlingStrategy":"validation","validationCode":"// List owned domains and bail out BEFORE hitting the quota\n$res = $guzzle->get(\"$apiBase/domains/\", ['headers' => ['Authorization' => \"Token $token\"]]);\n$owned = json_decode($res->getBody()->getContents(), true) ?: [];\nif (count($owned) >= DOMAIN_LIMIT) {\n    throw new \\Exception('At deSEC domain limit (' . DOMAIN_LIMIT . '). Remove a domain at desec.io first.');\n}","typeGuard":null,"tryCatchPattern":"try {\n    $domain = $manager->registerDomain($token, $slug);\n} catch (\\Exception $e) {\n    if (str_contains($e->getMessage(), 'reached its domain limit')) {\n        renderQuotaHelp($e->getMessage()); // link to desec.io domain management\n        return;\n    }\n    throw $e;\n}","preventionTips":["Check GET /domains/ count against the account's limit before any create","Offer a domain-list picker so users reuse owned domains instead of creating new ones","Surface 'delete unused domain at desec.io' guidance in the UI the moment 403 appears"],"tags":["php","desec","quota","domains"],"backgroundTag":"quota-exceeded","analyzedSha":"6b788eec5e61733cf03ed380a3572e43ae3f11ce","analyzedAt":"2026-08-21T05:47:24.382Z","schemaVersion":2},"datasetVersion":"2026-08-21T11:28:35.574Z"}