{"record":{"id":"f4d6aca53232ad92","repo":"louislam/uptime-kuma","slug":"failed-to-create-gift-wrapped-event-for-recipient","errorCode":null,"errorMessage":"Failed to create gift-wrapped event for recipient: ${error.message}","messagePattern":"Failed to create gift-wrapped event for recipient: (.+?)","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"server/notification-providers/nostr.js","lineNumber":33,"sourceCode":"        const recipientsPublicKeys = await this.getPublicKeys(notification.recipients);\n\n        // Create NIP-59 gift-wrapped events for each recipient\n        // This uses NIP-17 kind 14 (private direct message) wrapped with NIP-59\n        // to prevent metadata leakage (sender/recipient public keys are hidden)\n        const createdAt = Math.floor(Date.now() / 1000);\n        const events = [];\n        for (const recipientPublicKey of recipientsPublicKeys) {\n            const event = {\n                kind: 14, // NIP-17 private direct message\n                created_at: createdAt,\n                tags: [[\"p\", recipientPublicKey]],\n                content: msg,\n            };\n            try {\n                const wrappedEvent = nip59.wrapEvent(event, senderPrivateKey, recipientPublicKey);\n                events.push(wrappedEvent);\n            } catch (error) {\n                throw new Error(`Failed to create gift-wrapped event for recipient: ${error.message}`);\n            }\n        }\n\n        // Publish events to each relay\n        const relays = notification.relays.split(\"\\n\");\n        let successfulRelays = 0;\n        for (const relayUrl of relays) {\n            const relay = await Relay.connect(relayUrl);\n            let eventIndex = 0;\n\n            // Authenticate to the relay, if required\n            try {\n                await relay.publish(events[0]);\n                eventIndex = 1;\n            } catch (error) {\n                if (relay.challenge) {\n                    await relay.auth(async (evt) => {\n                        return finalizeEvent(evt, senderPrivateKey);","sourceCodeStart":15,"sourceCodeEnd":51,"githubUrl":"https://github.com/louislam/uptime-kuma/blob/6b5ea0155793e666666745fb8d6fef1e829543a2/server/notification-providers/nostr.js#L15-L51","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":null,"handlingStrategy":"type-guard","validationCode":"const senderKey = await this.getPrivateKey(notification.sender); // throws early with a clear message\nfor (const r of recipientsPublicKeys) {\n    if (!(r instanceof Uint8Array) && typeof r !== \"string\") {\n        throw new Error(`Recipient key has invalid type: ${typeof r}`);\n    }\n}","typeGuard":"/** @param {unknown} k */\nfunction isNostrKeyBytes(k) {\n    return k instanceof Uint8Array && k.length === 32 ||\n        (typeof k === \"string\" && /^[0-9a-fA-F]{64}$/.test(k));\n}","tryCatchPattern":"try {\n    const wrapped = nip59.wrapEvent(event, senderPrivateKey, recipientPublicKey);\n    events.push(wrapped);\n} catch (error) {\n    throw new Error(`wrapEvent failed for recipient (key type ${typeof recipientPublicKey}): ${error.message}`);\n}","preventionTips":["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."],"tags":["nostr","crypto","nip59","gift-wrap","key-format"],"backgroundTag":null,"analyzedSha":"6b5ea0155793e666666745fb8d6fef1e829543a2","analyzedAt":"2026-08-12T23:42:12.959Z","schemaVersion":2},"datasetVersion":"2026-08-13T04:17:16.726Z"}