appwrite/appwrite · error · Exception

Failed to rename certificate fullchain.pem. Let's Encrypt lo

Error message

Failed to rename certificate fullchain.pem. Let's Encrypt log: {stderr} ; {stdout}

What it means

PATCH /v1/functions/{functionId}/variables/{variableId} loads the parent function first; an empty getDocument('functions', $functionId) result throws function_not_found (src/Appwrite/Platform/Modules/Functions/Http/Variables/Update.php:89) before any update logic runs.

Source

Thrown at src/Appwrite/Certificates/LetsEncrypt.php:62

        // Prepare folder in storage for domain
        $path = APP_STORAGE_CERTIFICATES . '/' . $domain;
        if (!\is_readable($path)) {
            if (!\mkdir($path, 0755, true)) {
                throw new Exception('Failed to create path for certificate.');
            }
        }

        // Move generated files
        if (!@\rename('/etc/letsencrypt/live/' . $certName . '/cert.pem', APP_STORAGE_CERTIFICATES . '/' . $domain . '/cert.pem')) {
            throw new Exception('Failed to rename certificate cert.pem. Let\'s Encrypt log: ' . $stderr . ' ; ' . $stdout);
        }

        if (!@\rename('/etc/letsencrypt/live/' . $certName . '/chain.pem', APP_STORAGE_CERTIFICATES . '/' . $domain . '/chain.pem')) {
            throw new Exception('Failed to rename certificate chain.pem. Let\'s Encrypt log: ' . $stderr . ' ; ' . $stdout);
        }

        if (!@\rename('/etc/letsencrypt/live/' . $certName . '/fullchain.pem', APP_STORAGE_CERTIFICATES . '/' . $domain . '/fullchain.pem')) {
            throw new Exception('Failed to rename certificate fullchain.pem. Let\'s Encrypt log: ' . $stderr . ' ; ' . $stdout);
        }

        if (!@\rename('/etc/letsencrypt/live/' . $certName . '/privkey.pem', APP_STORAGE_CERTIFICATES . '/' . $domain . '/privkey.pem')) {
            throw new Exception('Failed to rename certificate privkey.pem. Let\'s Encrypt log: ' . $stderr . ' ; ' . $stdout);
        }

        $config = \implode(PHP_EOL, [
            "tls:",
            "  certificates:",
            "    - certFile: /storage/certificates/{$domain}/fullchain.pem",
            "      keyFile: /storage/certificates/{$domain}/privkey.pem"
        ]);

        // Save configuration into Traefik using our new cert files
        if (!\file_put_contents(APP_STORAGE_CONFIG . '/' . $domain . '.yml', $config)) {
            throw new Exception('Failed to save Traefik configuration.');
        }

View on GitHub (pinned to a1d520eea4)

Solutions

  1. Resolve the function id at runtime (list by name or a stable mapping) before updating variables
  2. Fail fast on the function GET in scripts that rotate many variables
  3. Store (functionId, variableId) pairs together, never separately

Example fix

// before
await functions.variables.update('fnct_stale', varId, undefined, 'rotated');

// after
const fn = await functions.get(fnId);
await functions.variables.update(fn.$id, varId, undefined, 'rotated');
Defensive patterns

Strategy: validation

Validate before calling

const fn = (await functions.list()).functions.find((f) => f.$id === fnId);
if (!fn) throw new Error(`function ${fnId} missing — cannot update its variables`);

Try / catch

try {
  await functions.variables.update(fnId, varId, key, value);
} catch (e) {
  if (e instanceof AppwriteException && e.code === 'function_not_found') {
    // re-resolve fnId and retry once, or mark the rotation entry skipped
  } else throw e;
}

Prevention

When it happens

Trigger: Updating a variable with a mistyped or stale functionId; patching against a deleted function; wrong project context in the SDK/API key.

Common situations: Configuration-rotation scripts holding hardcoded function ids across environment rebuilds; drift between environments where the function id differs.

Understand the failure class

Background: 'Could not be found', 'does not exist', 'not found in database': the resource-not-found family when an ID, slug, key, or URI lookup comes back empty — this error's family across 20 libraries.

Related errors


AI-assisted analysis of appwrite/appwrite@a1d520eea4 (2026-08-18). Data as JSON: /api/errors/ea32278f6b8e2e46. Report an issue: GitHub.