yikart/AiToEarn · warning
-1
-1
Error message
ChannelWebhookInvalidSignature
What it means
The Bilibili webhook provider rejects incoming webhook HTTP requests whose signature verification fails by responding 401 with code -1 and message ChannelWebhookInvalidSignature. The provider's verify(request) checked the request signature against the configured Bilibili webhook secret and it did not match, so the payload is not processed.
Source
Thrown at project/aitoearn-backend/apps/aitoearn-server/src/core/channels/platforms/bilibili/bilibili-webhook.provider.ts:41
} from './bilibili.interface'
type PersistedPublishDataOption = PublishRecord['dataOption']
@Injectable()
export class BilibiliWebhookProvider implements PlatformWebhookHandler {
private readonly logger = new Logger(BilibiliWebhookProvider.name)
constructor(
private readonly config: BilibiliConfig,
@Optional() private readonly publishRecordRepo?: PublishRecordRepository,
@Optional() private readonly stateService?: PublishStateService,
) {}
async handle(request: Request, response: Response): Promise<void> {
const verified = this.verify(request)
this.logger.log({ platform: AccountType.Bilibili, verified }, 'Bilibili webhook received')
if (!verified) {
response.status(401).json({ code: -1, message: getCodeMessage(ResponseCode.ChannelWebhookInvalidSignature, undefined, getLocale()) })
return
}
const body = this.parseBilibiliBody(request.body)
if (!body) {
response.status(200).json({ code: 0, message: 'ok' })
return
}
if (body.event === BilibiliWebhookEvent.VerifyWebhooks) {
response.status(200).json({ data: body.content.data })
return
}
await this.applyBilibiliPublishResult(body)
response.status(200).json({ code: 0, message: 'ok' })
}
private verify(request: RawBodyRequest): boolean {View on GitHub (pinned to d3aa8bea5b)
Solutions
- Confirm the webhook secret configured on the server matches the one registered with Bilibili
- Ensure signature verification reads the exact raw request body (no proxy re-serialization); configure the proxy to pass the body untouched
- Check that the correct environment's secret/env var is loaded (aitoearn.cn vs aitoearn.ai)
- Re-register the webhook URL/secret on the Bilibili side if it was rotated
Example fix
// before
// secret loaded from generic env
this.secret = process.env.WEBHOOK_SECRET
// after
// platform/env specific secret with startup validation
this.secret = process.env.BILIBILI_WEBHOOK_SECRET
if (!this.secret)
throw new Error('BILIBILI_WEBHOOK_SECRET is required') Defensive patterns
Strategy: validation
Validate before calling
const expected = crypto.createHmac('sha256', secret).update(rawBody).digest('hex')
if (req.headers['x-signature'] !== expected) return res.status(401).json({ code: -1 }) Type guard
function hasValidSignature(header: string | undefined, raw: Buffer, secret: string): boolean {
if (!header) return false
return crypto.timingSafeEqual(Buffer.from(header), crypto.createHmac('sha256', secret).update(raw).digest())
} Try / catch
app.post('/webhooks/bilibili', express.raw({ type: 'application/json' }), (req, res) => {
if (!hasValidSignature(req.headers['x-signature'], req.body, secret)) {
return res.status(401).json({ code: -1, message: 'ChannelWebhookInvalidSignature' })
}
// process payload
}) Prevention
- Store the Bilibili webhook secret in env per environment and validate at startup
- Configure proxies to pass the raw body byte-for-byte to the webhook route
- Rotate the secret on both Bilibili and server config simultaneously
- Log signature presence (not value) on failures for diagnostics
When it happens
Trigger: POST to the Bilibili webhook endpoint where the signature header is missing, computed with a different secret than the server's config, or the raw body was re-serialized (altering bytes) before HMAC verification.
Common situations: Webhook secret rotated on Bilibili's side but not in server env config; a proxy/gateway re-encoding the JSON body so the signed bytes differ; misconfigured per-environment secret (cn vs intl); replayed or forged requests.
Related errors
- -1
- ChannelWebhookInvalidSignature
- ChannelWebhookInvalidSignature
- ChannelWebhookInvalidSignature
- invalid_signature
AI-assisted analysis of yikart/AiToEarn@d3aa8bea5b (2026-08-31).
Data as JSON: /api/errors/086b746c4b96b27f.
Report an issue: GitHub.