paperclipai/paperclip · error
GitHub webhook configuration is incomplete
Error message
GitHub webhook configuration is incomplete
What it means
resyncGitHubAppWebhook validates the webhook URL and secret before PATCHing https://api.github.com/app/hook/config, throwing a plain Error('GitHub webhook configuration is incomplete') if the URL is not a clean https URL (no credentials/query/hash) or the webhookSecret is empty. This is a local configuration guard — no network request is made.
Source
Thrown at server/src/services/chat-github-webhook-config.ts:705
* A successful PATCH is configuration evidence only, never a signed ping or a
* successful chat round trip. See https://docs.github.com/en/rest/apps/webhooks.
*/
export async function resyncGitHubAppWebhook(input: {
fetch: typeof globalThis.fetch;
appToken: string;
webhookUrl: string;
webhookSecret: string;
}): Promise<void> {
const webhookUrl = new URL(input.webhookUrl);
if (
webhookUrl.protocol !== "https:" ||
webhookUrl.username ||
webhookUrl.password ||
webhookUrl.search ||
webhookUrl.hash ||
!input.webhookSecret
) {
throw new Error("GitHub webhook configuration is incomplete");
}
let response: Response;
try {
response = await input.fetch(GITHUB_APP_WEBHOOK_CONFIG_URL, {
method: "PATCH",
redirect: "error",
signal: AbortSignal.timeout(25_000),
headers: {
accept: "application/vnd.github+json",
authorization: `Bearer ${input.appToken}`,
"content-type": "application/json",
"x-github-api-version": "2022-11-28",
},
body: JSON.stringify({
url: input.webhookUrl,
content_type: "json",
insecure_ssl: "0",View on GitHub (pinned to 01ad858492)
Solutions
- Supply an https:// URL with no query string, fragment, or embedded credentials — put any token in the path instead.
- Provision the webhook secret: check the env var/secret manager is set and non-empty before calling resync.
- Normalize the URL: strip trailing query/hash, ensure scheme is https, then pass the cleaned value.
- Fail fast in your own startup code with a clear message if webhookUrl/webhookSecret are missing or non-https.
Example fix
// before
await resyncGitHubAppWebhook({ fetch, appToken, webhookUrl: process.env.WEBHOOK_URL, webhookSecret: process.env.WEBHOOK_SECRET });
// after
const webhookUrl = process.env.WEBHOOK_URL;
const webhookSecret = process.env.WEBHOOK_SECRET;
const u = new URL(webhookUrl);
if (u.protocol !== "https:" || u.search || u.hash || u.username || u.password || !webhookSecret) {
throw new Error("WEBHOOK_URL must be a clean https URL and WEBHOOK_SECRET must be set");
}
await resyncGitHubAppWebhook({ fetch, appToken, webhookUrl, webhookSecret }); Defensive patterns
Strategy: validation
Validate before calling
function validateWebhookConfig(webhookUrl: string, webhookSecret: string): void {
const u = new URL(webhookUrl);
if (u.protocol !== "https:" || u.username || u.password || u.search || u.hash) throw new Error("webhookUrl must be a clean https URL");
if (!webhookSecret) throw new Error("webhookSecret is required");
} Type guard
null
Try / catch
try {
await resyncGitHubAppWebhook({ fetch, appToken, webhookUrl, webhookSecret });
} catch (e) {
if (e instanceof Error && e.message === "GitHub webhook configuration is incomplete") {
throw new ConfigError("Set WEBHOOK_URL (https, no query/hash/credentials) and WEBHOOK_SECRET before resync");
}
throw e;
} Prevention
- Require an https callback URL with tokens in the path, never in the query string
- Fail fast at startup when WEBHOOK_SECRET is unset instead of resyncing with an empty secret
- Validate URL shape with new URL() before calling resync
- Keep the webhook secret in a secret manager, not inline config files
When it happens
Trigger: webhookUrl passed as http://, with an embedded user:pass, with ?query or #fragment, or not a parseable URL (new URL throws before the check); webhookSecret empty string, undefined, or a placeholder not yet configured.
Common situations: Dev environment running with http://localhost callback (not https); secret not provisioned from env/secret manager (empty GITHUB_APP_WEBHOOK_SECRET); a tunneling URL like https://tunnel.example/cb?token=xyz containing a query string; forgetting to URL-encode/remove fragments.
Understand the failure class
Background: "Invalid value" and "allowed values are" config errors: what your library rejected and how to fix it — this error's family across 41 libraries.
Related errors
- github_webhook_recovery_invalid_response
- ${label} must be an integer between 1 and ${maximum}.
- PAPERCLIP_EVAL_MAX_CAMPAIGN_COST_USD must be a positive fini
- Runner live rotation requires a valid generated-at time
- --agent-name cannot be empty.
AI-assisted analysis of paperclipai/paperclip@01ad858492 (2026-09-10).
Data as JSON: /api/errors/f2af5bff8de6f64b.
Report an issue: GitHub.