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

  1. Ensure notification.sender is the sender's nsec private key so getPrivateKey returns the correct decoded bytes.
  2. Ensure recipients are npub values so getPublicKeys returns valid 32-byte public keys.
  3. Pin/upgrade nostr-tools to a version compatible with the NIP-59 API used here and check wrapEvent's signature expectations.
  4. 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

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


AI-assisted analysis of louislam/uptime-kuma@6b5ea01557 (2026-08-12). Data as JSON: /api/errors/f4d6aca53232ad92. Report an issue: GitHub.