{"id":9912,"library":"magic-wormhole","title":"Magic-Wormhole","description":"Magic-Wormhole is a Python library and command-line tool for securely transferring arbitrary data (files, directories, or text) between computers using a short, human-speakable 'wormhole code'. It leverages PAKE (Password-Authenticated Key Exchange) for secure key establishment. It is actively maintained at version 0.23.0 with a focus on security, reliability, and ease of use, releasing updates on a moderate cadence.","status":"active","version":"0.23.0","language":"en","source_language":"en","source_url":"https://github.com/warner/magic-wormhole","tags":["security","file-transfer","p2p","cli","cryptography","asyncio"],"install":[{"cmd":"pip install magic-wormhole","lang":"bash","label":"Install latest version"}],"dependencies":[{"reason":"Provides core cryptographic primitives for secure communication.","package":"pynacl","optional":false},{"reason":"Asynchronous networking framework used internally for handling connections.","package":"twisted","optional":false},{"reason":"WebSocket client/server implementation used with Twisted for relay communication.","package":"autobahn","optional":false}],"imports":[{"note":"This is the primary class for programmatic send/receive operations. Direct imports from lower-level modules are not recommended for typical usage.","symbol":"Wormhole","correct":"from magic_wormhole.api import Wormhole"}],"quickstart":{"code":"import asyncio\nfrom magic_wormhole.api import Wormhole\n\nasync def send_data_example():\n    w = Wormhole()\n    code = await w.get_code()\n    print(f\"Your wormhole code is: {code}\")\n    print(\"Waiting for recipient to connect...\")\n    \n    # In a real scenario, you'd wait for connection confirmation before sending sensitive data.\n    # The 'send_data' or 'send_file' automatically handles the rendezvous.\n\n    data_to_send = b\"Hello, magic wormhole!\"\n    print(f\"Sending: '{data_to_send.decode()}'\")\n    await w.send_data(data_to_send)\n    print(\"Data sent.\")\n    \n    # The wormhole object must be closed to release resources and ensure clean exit.\n    await w.close()\n\nif __name__ == \"__main__\":\n    # This runs the asynchronous example using asyncio\n    asyncio.run(send_data_example())","lang":"python","description":"This quickstart demonstrates how to programmatically send data using the `magic-wormhole` API. Run this script, and it will output a wormhole code. On another machine, a recipient would initiate a transfer by calling `Wormhole.from_code(code)` and then `await w.receive_data()` (or `receive_file()`). The API is asynchronous, requiring `async`/`await` and `asyncio.run()`."},"warnings":[{"fix":"Check network connectivity and firewall settings. Ensure DNS resolution for `relay.magic-wormhole.io`. For critical applications, consider deploying and configuring your own private relay server (see `wormhole-relay-server` project) and specify its URL to the `Wormhole` constructor: `Wormhole(relay_url='ws://your.relay.server:4000/v1')`.","message":"By default, `magic-wormhole` relies on a public relay server for initial connection bootstrapping. If this server is unreachable due to network issues, firewalls, or outages, connections will fail.","severity":"gotcha","affected_versions":"All versions using the default relay server."},{"fix":"Ensure all API calls to `Wormhole` methods (like `get_code()`, `send_data()`, `receive_data()`) are properly `await`-ed within `async` functions, and the top-level execution is managed by `asyncio.run()`.","message":"Programmatic use of the `magic-wormhole` API is inherently asynchronous and requires managing an event loop (e.g., `asyncio`). Attempting to call async methods without `await` or outside an `async` context will result in runtime errors.","severity":"gotcha","affected_versions":"All versions (since 0.11.0, when the API transitioned to returning Deferreds/Futures)."},{"fix":"Generate a new wormhole code for each distinct transfer operation to ensure maximum security and reliability.","message":"Wormhole codes are designed for one-time, ephemeral use. While the library might allow it, reusing a generated code for multiple, separate transfers or across long durations is not the intended use and can lead to unexpected behavior or security issues.","severity":"gotcha","affected_versions":"All versions."}],"env_vars":null,"last_verified":"2026-04-17T00:00:00.000Z","next_check":"2026-07-16T00:00:00.000Z","problems":[{"fix":"Verify your internet connection and DNS settings. Check firewall rules to ensure outgoing WebSocket connections (port 443 or 80 for `wss://` or `ws://` respectively, or port 4000 for specific relay setup) are allowed. You might need to specify a custom relay server if the default one is consistently unreachable.","cause":"The system was unable to resolve the hostname of the default `magic-wormhole` relay server, likely due to network connectivity issues, misconfigured DNS, or a restrictive firewall.","error":"twisted.internet.error.DNSLookupError: Hostname 'relay.magic-wormhole.io' could not be resolved"},{"fix":"Ensure all `magic_wormhole` API calls (e.g., `w.get_code()`, `w.send_data()`) are prefixed with `await`. Also, confirm that the function containing these calls is declared with `async def` and is ultimately run by `asyncio.run()`.","cause":"This typically occurs when an asynchronous function or method is called without the `await` keyword, causing it to return a `coroutine` object which then gets lost, or if a non-async function is mistakenly awaited.","error":"TypeError: object NoneType can't be used in 'await' expression"},{"fix":"Communicate with the recipient to ensure they are ready and have not cancelled the operation. Both sender and receiver should restart their respective `magic-wormhole` processes, typically with a new wormhole code.","cause":"The remote party (recipient) closed their `magic-wormhole` client or explicitly cancelled the transfer before the negotiation could complete or the data transfer could begin.","error":"Wormhole negotiation failed: recipient cancelled"}]}