Significant-Gravitas/AutoGPT · error · HTTPException

str(e)

Error message

str(e)

What it means

A 500 from the Postmark one-click unsubscribe endpoint when unsubscribe_user_by_token raises any exception. The detail embeds str(e), so the concrete cause is typically an invalid/expired unsubscribe token, a missing user preference record, or a Postmark settings problem — visible in the message and in the logged traceback.

Source

Thrown at autogpt_platform/backend/backend/api/features/postmark/postmark.py:44

logger = logging.getLogger(__name__)
settings = Settings()

router = APIRouter()

postmark_api_key_auth = APIKeyAuthenticator(
    "X-Postmark-Webhook-Token",
    settings.secrets.postmark_webhook_token,
)


@router.post("/unsubscribe", summary="One Click Email Unsubscribe")
async def unsubscribe_via_one_click(token: Annotated[str, Query()]):
    logger.info("Received unsubscribe request from One Click Unsubscribe")
    try:
        await unsubscribe_user_by_token(token)
    except Exception as e:
        logger.exception("Unsubscribe failed: %s", e)
        raise HTTPException(
            status_code=500,
            detail={"message": str(e), "hint": "Verify Postmark token settings."},
        )
    return JSONResponse(status_code=200, content={"status": "ok"})


@router.post(
    "/",
    dependencies=[Security(postmark_api_key_auth)],
    summary="Handle Postmark Email Webhooks",
)
async def postmark_webhook_handler(
    webhook: Annotated[
        PostmarkWebhook,
        Body(discriminator="RecordType"),
    ]
):
    logger.info(f"Received webhook from Postmark: {webhook}")

View on GitHub (pinned to 9c8bb5550f)

Solutions

  1. Inspect the response message and the logged 'Unsubscribe failed' traceback to identify the exact failure.
  2. If the token is expired/invalid, regenerate the unsubscribe link or unsubscribe via the app's account settings page.
  3. Verify Postmark-related secrets/settings (settings.secrets.postmark_webhook_token etc.) are set for the environment.
  4. URL-decode the token exactly as sent and confirm it isn't truncated by the mail client.

Example fix

# before — token from an old email
curl -X POST 'https://app.example.com/api/unsubscribe?token=stale-token'
# after — fresh link from a current email
curl -X POST 'https://app.example.com/api/unsubscribe?token=<token-from-latest-email>'
Defensive patterns

Strategy: try-catch

Validate before calling

// Check token shape before calling
if (!/^[A-Za-z0-9_-]{20,}$/.test(token)) {
  throw new Error('malformed unsubscribe token');
}

Type guard

const isValidTokenShape = (t: string) => /^[A-Za-z0-9_-]{20,}$/.test(t);

Try / catch

try { await unsubscribe(token); }
catch (e) {
  if (e.status === 500 && /expired|invalid/i.test(e.detail?.message ?? '')) {
    showManualUnsubscribeFallback(); // account-settings link
  } else throw e;
}

Prevention

When it happens

Trigger: POST /api/unsubscribe?token=... with a token that fails validation, is expired, doesn't map to a subscription, or when the unsubscribe routine hits a DB error. Postmark's webhook/one-click flow hitting the endpoint after tokens were rotated also triggers it.

Common situations: Old emails containing tokens invalidated by a key/secret rotation; postmark_webhook_token or related settings misconfigured; database unreachable when persisting the preference; token URL-mangled by mail clients (truncated or HTML-escaped).

Related errors


AI-assisted analysis of Significant-Gravitas/AutoGPT@9c8bb5550f (2026-08-14). Data as JSON: /api/errors/8826c1c5c5a4d2f9. Report an issue: GitHub.