{"record":{"id":"1ef7b85e65bb391e","repo":"nextcloud/all-in-one","slug":"could-not-register-a-free-dedyn-io-domain-after-m","errorCode":null,"errorMessage":"Could not register a free dedyn.io domain after {maxSlugAttempts} attempts. Please try again.","messagePattern":"Could not register a free dedyn\\.io domain after (.+?) attempts\\. Please try again\\.","errorType":"exception","errorClass":"\\Exception","httpStatus":422,"severity":"warning","filePath":"php/src/Desec/DesecManager.php","lineNumber":331,"sourceCode":"                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    }\n\n    /**\n     * Checks whether the authenticated account already owns the given domain.\n     *\n     * Used to recover from a failed creation when the user is reusing a slug they\n     * registered earlier: GET /domains/{name}/ returns 200 only for a domain the\n     * token's account owns, 404 otherwise.\n     *\n     * @throws \\Exception on network failure or an unexpected HTTP response\n     */\n    private function ownsDomain(string $token, string $domain): bool {\n        try {\n            $res = $this->guzzleClient->get($this->configurationManager->desecApiBase . '/domains/' . $domain . '/', [\n                'headers' => ['Authorization' => 'Token ' . $token],\n            ]);\n        } catch (TransferException $e) {\n            throw new \\Exception('Could not reach the deSEC API: ' . $e->getMessage());","sourceCodeStart":313,"sourceCodeEnd":349,"githubUrl":"https://github.com/nextcloud/all-in-one/blob/6b788eec5e61733cf03ed380a3572e43ae3f11ce/php/src/Desec/DesecManager.php#L313-L349","documentation":"Random-slug mode tried MAX_SLUG_ATTEMPTS (5) times to register a randomly generated 10-hex-character <slug>.dedyn.io name and every attempt returned 409 (collision), because collisions are the only outcome that `continue`s the loop. The exception fires after the fifth consecutive collision.","triggerScenarios":"Five consecutive 409s on random bin2hex(random_bytes(5)) names — each attempt retries with a fresh random slug, so reaching this requires astronomically bad luck or a deSEC-side anomaly that answers every POST /domains/ with 409.","commonSituations":"Practically never in normal operation; if seen, suspect the API is misbehaving (e.g. proxy or misrouted desecApiBase returning 409 for everything) rather than genuine collisions.","solutions":["Simply retry — fresh random slugs are drawn each run","If it recurs, verify desecApiBase and that requests actually reach desec.io (a proxy answering 409 for everything would explain it)","Fall back to a user-chosen unique slug to bypass random generation"],"exampleFix":null,"handlingStrategy":"retry","validationCode":null,"typeGuard":null,"tryCatchPattern":"try {\n    $domain = $manager->registerDomain($token, ''); // '' = random slug\n} catch (\\Exception $e) {\n    if (str_contains($e->getMessage(), 'Could not register a free dedyn.io domain after')) {\n        sleep(1);\n        return $manager->registerDomain($token, ''); // fresh random slugs next round\n    }\n    throw $e;\n}","preventionTips":["Five consecutive 409s on random 10-hex-char names is an anomaly, not bad luck — verify the endpoint is really desec.io","Always allow the empty-slug option in the UI so users can fall back to randomness","Don't increase attempt counts without evidence; the math says collisions are ~impossible"],"tags":["php","desec","retry","domains","collision"],"backgroundTag":"retry-exhausted","analyzedSha":"6b788eec5e61733cf03ed380a3572e43ae3f11ce","analyzedAt":"2026-08-21T05:47:24.382Z","schemaVersion":2},"datasetVersion":"2026-08-21T11:28:35.574Z"}