louislam/uptime-kuma · error · Error
Failed to create gift-wrapped event for recipient: ${error.m
Error message
Failed to create gift-wrapped event for recipient: ${error.message} What it means
Inside the Nostr provider's per-recipient loop, nip59.wrapEvent() is called to build a NIP-59 gift-wrapped (sealed + rumor) event from a kind-14 NIP-17 private direct message. If wrapEvent throws (bad key types, malformed event, or a nostr-tools internal failure), the provider wraps it as 'Failed to create gift-wrapped event for recipient: <inner.message>'. This is a cryptographic/format failure, not a network failure.
Source
Thrown at server/notification-providers/nostr.js:33
const recipientsPublicKeys = await this.getPublicKeys(notification.recipients);
// Create NIP-59 gift-wrapped events for each recipient
// This uses NIP-17 kind 14 (private direct message) wrapped with NIP-59
// to prevent metadata leakage (sender/recipient public keys are hidden)
const createdAt = Math.floor(Date.now() / 1000);
const events = [];
for (const recipientPublicKey of recipientsPublicKeys) {
const event = {
kind: 14, // NIP-17 private direct message
created_at: createdAt,
tags: [["p", recipientPublicKey]],
content: msg,
};
try {
const wrappedEvent = nip59.wrapEvent(event, senderPrivateKey, recipientPublicKey);
events.push(wrappedEvent);
} catch (error) {
throw new Error(`Failed to create gift-wrapped event for recipient: ${error.message}`);
}
}
// Publish events to each relay
const relays = notification.relays.split("\n");
let successfulRelays = 0;
for (const relayUrl of relays) {
const relay = await Relay.connect(relayUrl);
let eventIndex = 0;
// Authenticate to the relay, if required
try {
await relay.publish(events[0]);
eventIndex = 1;
} catch (error) {
if (relay.challenge) {
await relay.auth(async (evt) => {
return finalizeEvent(evt, senderPrivateKey);View on GitHub (pinned to 6b5ea01557)
Solutions
- Ensure notification.sender is the sender's nsec private key so getPrivateKey returns the correct decoded bytes.
- Ensure recipients are npub values so getPublicKeys returns valid 32-byte public keys.
- Pin/upgrade nostr-tools to a version compatible with the NIP-59 API used here and check wrapEvent's signature expectations.
- Reproduce wrapEvent in isolation for one recipient to capture the precise inner error.
Defensive patterns
Strategy: type-guard
Validate before calling
const senderKey = await this.getPrivateKey(notification.sender); // throws early with a clear message
for (const r of recipientsPublicKeys) {
if (!(r instanceof Uint8Array) && typeof r !== "string") {
throw new Error(`Recipient key has invalid type: ${typeof r}`);
}
} Type guard
/** @param {unknown} k */
function isNostrKeyBytes(k) {
return k instanceof Uint8Array && k.length === 32 ||
(typeof k === "string" && /^[0-9a-fA-F]{64}$/.test(k));
} Try / catch
try {
const wrapped = nip59.wrapEvent(event, senderPrivateKey, recipientPublicKey);
events.push(wrapped);
} catch (error) {
throw new Error(`wrapEvent failed for recipient (key type ${typeof recipientPublicKey}): ${error.message}`);
} Prevention
- Decode and type-check sender/recipient keys once up front, before the wrap loop.
- Keep nostr-tools version pinned to match the NIP-59 API you call.
- Unit-test wrapEvent with a known-good key pair to isolate crypto failures.
When it happens
Trigger: senderPrivateKey is not the hex/bytes shape nostr-tools expects (e.g. it was fed an npub or a string instead of decoded key data), recipientPublicKey is not valid bytes/hex for the seal recipient, or the event payload (tags/content/created_at) is malformed in a way nip59 rejects.
Common situations: Sender field entered as an npub (public) instead of an nsec (private); recipient public keys decoded but the decode returned unexpected data type; nostr-tools version change altering wrapEvent's accepted inputs.
Related errors
- Failed to decode private key for sender ${sender}: ${error.m
- Recipient ${recipient} is not an npub
- Error decoding recipient ${recipient}: ${error}
AI-assisted analysis of louislam/uptime-kuma@6b5ea01557 (2026-08-12).
Data as JSON: /api/errors/f4d6aca53232ad92.
Report an issue: GitHub.