{"record":{"id":"d133031e02b6b96f","repo":"coollabsio/coolify","slug":"failed-to-generate-new-type-key-message","errorCode":null,"errorMessage":"Failed to generate new {$type} key: {message}","messagePattern":"Failed to generate new (.+?) key: (.+?)","errorType":"exception","errorClass":"Exception","httpStatus":null,"severity":"error","filePath":"app/Models/PrivateKey.php","lineNumber":178,"sourceCode":"    }\n\n    public static function generateNewKeyPair($type = 'rsa')\n    {\n        try {\n            $instance = new self;\n            $instance->rateLimit(10);\n            $name = generate_random_name();\n            $description = 'Created by Coolify';\n            $keyPair = generateSSHKey($type === 'ed25519' ? 'ed25519' : 'rsa');\n\n            return [\n                'name' => $name,\n                'description' => $description,\n                'private_key' => $keyPair['private'],\n                'public_key' => $keyPair['public'],\n            ];\n        } catch (\\Throwable $e) {\n            throw new \\Exception(\"Failed to generate new {$type} key: \".$e->getMessage());\n        }\n    }\n\n    public static function extractPublicKeyFromPrivate($privateKey)\n    {\n        try {\n            $key = PublicKeyLoader::load($privateKey);\n\n            return $key->getPublicKey()->toString('OpenSSH', ['comment' => '']);\n        } catch (\\Throwable $e) {\n            return null;\n        }\n    }\n\n    public static function validateAndExtractPublicKey($privateKey)\n    {\n        $isValid = self::validatePrivateKey($privateKey);\n        $publicKey = $isValid ? self::extractPublicKeyFromPrivate($privateKey) : '';","sourceCodeStart":160,"sourceCodeEnd":196,"githubUrl":"https://github.com/coollabsio/coolify/blob/70b9acc42467278373e00de77abb40684e25b395/app/Models/PrivateKey.php#L160-L196","documentation":"Thrown by PrivateKey::generateNewKeyPair() (app/Models/PrivateKey.php:178). This static helper rate-limits itself ($instance->rateLimit(10)), maps the requested type to 'ed25519' or 'rsa', then shells out via generateSSHKey($type). Any Throwable — a rate-limit exception, a missing ssh-keygen binary, or a process error — is caught and re-wrapped as \"Failed to generate new {$type} key: {message}\". Note the rate limiter (10 attempts) throws TooManyAttemptsException, which is a Throwable, so hitting the limit also surfaces through this message with a misleading 'key generation' framing.","triggerScenarios":"Calling PrivateKey::generateNewKeyPair('ed25519') or ('rsa') more than 10 times in a short window (rate limit), or when ssh-keygen is absent/broken in the Coolify container, or the temp area used by generateSSHKey() is not writable.","commonSituations":"UI/script generating many key pairs in a loop (e.g. seeding servers) and tripping the 10-per-window limiter; slim/custom Coolify images without openssh-client; read-only /tmp inside the container.","solutions":["If you generated several keys recently, wait for the rate-limit window to decay (limit is 10) and retry.","Verify ssh-keygen exists in the container: docker exec coolify which ssh-keygen.","Check the appended {message} — it distinguishes 'Too many attempts' from an ssh-keygen/exec failure.","Only pass 'rsa' or 'ed25519'; other values are silently coerced to rsa but the message will echo your original $type."],"exampleFix":"// before\nfor ($i = 0; $i < 15; $i++) {\n    $pair = PrivateKey::generateNewKeyPair('ed25519'); // trips 10/attempt limit\n}\n\n// after — pace generation or use RateLimiter::tooManyAttempts to precheck\nuse Illuminate\\Support\\Facades\\RateLimiter;\nif (RateLimiter::tooManyAttempts('generate-key:'.auth()->id(), 10)) {\n    return back()->withErrors(['key' => 'Slow down — key generation is rate limited.']);\n}\n$pair = PrivateKey::generateNewKeyPair('ed25519');","handlingStrategy":"retry","validationCode":"// Pre-check the rate limit used by generateNewKeyPair\nuse Illuminate\\Support\\Facades\\RateLimiter;\n$key = 'generate-key:'.(auth()->id() ?? 'system');\nif (RateLimiter::tooManyAttempts($key, 10)) {\n    $seconds = RateLimiter::availableIn($key);\n    abort(429, \"Key generation rate limited. Retry in {$seconds}s.\");\n}","typeGuard":null,"tryCatchPattern":"try {\n    $pair = PrivateKey::generateNewKeyPair('ed25519');\n} catch (\\Exception $e) {\n    if (str_contains($e->getMessage(), 'Too Many Attempts')) {\n        // back off and retry after RateLimiter::availableIn()\n        return retry(after: fn () => RateLimiter::availableIn($key), callback: fn () => PrivateKey::generateNewKeyPair('ed25519'));\n    }\n    throw $e; // ssh-keygen/exec failure — check binary availability\n}","preventionTips":["Batch key generation with pacing; the limiter is 10 attempts per window per instance model.","Confirm ssh-keygen exists in the image before shipping custom Coolify containers.","Read the appended {message} to distinguish rate limiting from a missing binary."],"tags":["coolify","ssh-key","rate-limiting","process-execution"],"backgroundTag":"ssh-key-generation-failed","analyzedSha":"70b9acc42467278373e00de77abb40684e25b395","analyzedAt":"2026-08-17T01:41:01.313Z","schemaVersion":2},"datasetVersion":"2026-08-17T04:17:16.089Z"}