HeyPuter/puter · error · HttpError

account_suspended

account_suspended

Error message

Account suspended

What it means

Thrown by POST /writeFile when the target entry's owner has the `suspended` flag set. Even though the signature is cryptographically valid, a suspended owner's files must not be mutated. Because signed URLs are long-lived by default, this guard blocks signatures minted before the suspension.

Source

Thrown at src/backend/controllers/fs/LegacyFSController.ts:1408

        );

        const uid = typeof query.uid === 'string' ? query.uid : '';
        const targetEntry = await resolveV1Selector(this.stores.fsEntry, {
            uid,
        });
        if (!targetEntry)
            throw new HttpError(404, 'Item not found', {
                legacyCode: 'not_found',
            });

        // Owner suspension check.
        const owner = await this.stores.user.getById(targetEntry.userId);
        if (!owner)
            throw new HttpError(500, 'Owner not found', {
                legacyCode: 'internal_error',
            });
        if ((owner as { suspended?: unknown }).suspended)
            throw new HttpError(401, 'Account suspended', {
                legacyCode: 'account_suspended',
            });

        const userId = targetEntry.userId;
        const operation =
            typeof query.operation === 'string' ? query.operation : 'write';

        // A valid write signature authorises overwriting the file's bytes,
        // not structural changes. Restrict copy/move/mkdir/rename/delete/trash
        // to a caller authenticated as the owner — otherwise a recipient of a
        // write-share could relocate or destroy the source via this endpoint.
        if (operation !== 'write' && req.actor?.user?.id !== userId) {
            throw new HttpError(
                403,
                `'${operation}' via signed URL requires owner authentication`,
                { legacyCode: 'forbidden' },
            );
        }

View on GitHub (pinned to 908ec23eda)

Solutions

  1. Stop using signed URLs for the suspended owner's content; resolve the suspension with the account admin first.
  2. If you are a collaborator, ask the owner to restore their account, then re-sign.
  3. Surface a clear 'account suspended' message to end users rather than retrying.
Defensive patterns

Strategy: try-catch

Try / catch

try { await fetch(writeUrl, { method:'POST', body: form }); }
catch (e) {
  if (e.code === 'account_suspended') {
    // stop retrying; surface 'owner account suspended' to the user
  } else throw e;
}

Prevention

When it happens

Trigger: POST /writeFile (any operation) where the file owner's account was suspended after the URL was signed; writing to a shared file whose owner got suspended.

Common situations: Account suspended for abuse/non-payment while collaborators hold valid signed URLs; reusing an old signed URL after an account action.

Related errors


AI-assisted analysis of HeyPuter/puter@908ec23eda (2026-08-12). Data as JSON: /api/errors/9b15f45b5b1a3456. Report an issue: GitHub.