{"record":{"id":"d1adab4e8249becd","repo":"Significant-Gravitas/AutoGPT","slug":"e","errorCode":null,"errorMessage":"{e}","messagePattern":"\\{e\\}","errorType":"http","errorClass":"HTTPException","httpStatus":404,"severity":"warning","filePath":"autogpt_platform/backend/backend/api/features/integrations/router.py","lineNumber":709,"sourceCode":"    webhook_id: Annotated[str, Path(title=\"Our ID for the webhook\")],\n):\n    logger.debug(f\"Received {provider.value} webhook ingress for ID {webhook_id}\")\n    webhook_manager = get_webhook_manager(provider)\n    try:\n        webhook = await get_webhook(webhook_id, include_relations=True)\n        # Sanity check: `provider` from URL and fetched webhook must match.\n        # Otherwise the URL provider's verifier runs instead of the webhook's\n        # own (a no-op for unsigned providers like Compass), bypassing it.\n        if webhook.provider.value.lower() != provider.value.lower():\n            logger.warning(\n                f\"Webhook #{webhook_id} provider mismatch: \"\n                f\"registered as {webhook.provider.value}, ingress via {provider.value}\"\n            )\n            # Same as the actual \"webhook not found\" response to conceal existence\n            raise NotFoundError(f\"Webhook #{webhook_id} not found\")\n    except NotFoundError as e:\n        logger.warning(f\"Webhook payload received for unknown webhook #{webhook_id}\")\n        raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail=str(e))\n    logger.debug(f\"Webhook #{webhook_id}: {webhook}\")\n\n    user_id = webhook.user_id\n    try:\n        credentials = (\n            await creds_manager.get(user_id, webhook.credentials_id)\n            if webhook.credentials_id\n            else None\n        )\n    except NotFoundError as e:\n        logger.warning(f\"Webhook payload received for unknown webhook #{webhook_id}\")\n        raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail=str(e))\n\n    # Run provider signature verification (no-op for providers whose protocol\n    # has no signing scheme). 403 on failure; not 404 — that would leak\n    # webhook existence.\n    try:\n        await webhook_manager.verify_signature(webhook, request)","sourceCodeStart":691,"sourceCodeEnd":727,"githubUrl":"https://github.com/Significant-Gravitas/AutoGPT/blob/9c8bb5550f446ba5d3046b78896578742495b3cf/autogpt_platform/backend/backend/api/features/integrations/router.py#L691-L727","documentation":"During webhook ingress, after the webhook row is found, the endpoint loads the credentials attached to the webhook (webhook.credentials_id) via creds_manager.get(). If that credentials record no longer exists, the resulting NotFoundError is caught and converted to HTTP 404 with detail 'Webhook #{webhook_id} not found'. The message is intentionally the same as the not-found case so callers cannot distinguish a dangling-credentials webhook from a missing one.","triggerScenarios":"The webhook exists but its credentials_id points at a deleted/revoked credentials record — e.g. the user deleted the credential in the credentials UI without the webhook being pruned, or a credential store sync removed the row. Any provider POST to /integrations/{provider}/webhooks/{webhook_id}/webhook for that webhook returns 404.","commonSituations":"Credential deleted while a webhook registered against it was still linked to a node/preset; multi-instance deployments where one node's credential store write hasn't propagated; manual DB cleanup that removed credentials but not webhooks.","solutions":["List webhooks for the user (GET /integrations/webhooks) and check whether the failing webhook's credentials_id still resolves via GET /integrations/{provider}/credentials.","Re-create or re-attach valid credentials on the provider block that owns the webhook, which re-registers the webhook with a live credentials_id.","If the credential is gone on purpose, delete/unlink the webhook (DELETE credentials with force, or remove the node webhook binding) so the provider stops delivering to a dead URL.","Check backend logs: the warning 'Webhook payload received for unknown webhook #{webhook_id}' plus a successful webhook fetch in the debug line above distinguishes the dangling-credentials case from a truly missing webhook."],"exampleFix":null,"handlingStrategy":"validation","validationCode":"# Before sending traffic, confirm webhook.credentials_id still resolves\nwh = await get_webhook_by_id(webhook_id)\nif wh.get(\"credentials_id\"):\n    creds = await client.get(f\"/integrations/{provider}/credentials\")\n    if wh[\"credentials_id\"] not in {c[\"id\"] for c in creds.json()}:\n        re_register_webhook(provider)  # dangling credentials reference","typeGuard":null,"tryCatchPattern":null,"preventionTips":["When deleting credentials, always go through the platform delete flow so linked webhooks are pruned or unlinked.","Periodically reconcile: list webhooks and verify each credentials_id exists.","Don't delete credentials out from under agents that use their webhooks."],"tags":["webhook","credentials","http-404","dangling-reference"],"backgroundTag":null,"analyzedSha":"9c8bb5550f446ba5d3046b78896578742495b3cf","analyzedAt":"2026-08-14T17:17:21.957Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}