Sending and receiving
Floe says "Open in your browser"
Floe says "Open in your browser"
The transfer never starts or is stuck connecting
The transfer never starts or is stuck connecting
- The sender must stay in the session for the entire transfer. If the sender closes the browser tab, quits the desktop app, or stops
floe send, the session ends. - The recipient must actually open the shared link (or run
floe receive). In the browser and the desktop app the transfer then begins on its own.floe receiveasks you to confirm first, so a sender can sit on “Connecting” while the recipient has simply not answered theAccept? [Y/n]prompt. Pass-yto skip it. - On strict networks, a direct path may not be possible. Relay fallback has to stay on for Floe to route through the encrypted relay. In the browser it is a sender-side setting, shown as the Network relay fallback checkbox once the sender has picked files, and it is on by default. If you are the browser recipient you have no such control, so ask the sender to check it. Floe’s own error message calls it “Network Relay”. On the CLI the equivalent is not passing
--no-relay, which drops TURN on whichever side passes it. The desktop app has no relay-fallback control at all, so the relay is always available there.
Transfer blocked: relay limit exceeded
Transfer blocked: relay limit exceeded
- Use a standard home or personal Wi-Fi network.
- Disconnect from any VPN.
- Avoid strict corporate or university networks.
- Try a personal mobile hotspot.
The transfer is slow
The transfer is slow
Downloads fail or behave oddly on iOS
Downloads fail or behave oddly on iOS
CLI
The CLI cannot reach the server
The CLI cannot reach the server
https://api.floe.one by default. If you are using a self-hosted instance, pass --server with your signaling server URL, and make sure both the sender and receiver use the same value.If the CLI is reaching an address you did not ask for, check your environment. FLOE_SERVER overrides the default whenever --server is not passed, and FLOE_WEB does the same for the browser link that floe send prints. Check with $env:FLOE_SERVER in PowerShell, or echo $FLOE_SERVER on macOS and Linux. See Against a Self-Hosted Server.A browser recipient cannot join my CLI transfer
A browser recipient cannot join my CLI transfer
floe send with browser recipients, and the code with CLI or desktop recipients, either of which also accepts the link.The CLI is slow to connect when a VPN or virtual machine is running
The CLI is slow to connect when a VPN or virtual machine is running
--iface more than once to allow several interfaces. The flag is an allowlist, not a preference: only the interfaces you name are used, so drop it again if you move to a different network, or the connection will fail outright rather than merely be slow. Temporarily quitting the VPN during a transfer also resolves it.Cannot transfer: your floe is too old for this peer
Cannot transfer: your floe is too old for this peer
Cannot transfer: your floe is too old for this peer and Cannot transfer: peer's floe is too old. Peers on different Floe versions normally transfer fine, so a small version difference (for example v1.5.4 and v1.5.5) is never a problem. Either message only appears if a release changed the transfer protocol in a way the two versions cannot bridge.The message prints both sides as You: and Peer:, each with its protocol range and release version. On current releases each side words the message from its own point of view, so the side named as too old is the one to update. Older releases printed the receiver’s wording unchanged on the sender’s side, so there a sender could be told “your floe is too old” while it was the receiver that needed updating; when in doubt, go by the version strings and update the older one. If both versions look current, update both.floe update command, so update it the way you installed it. From the Microsoft Store, open Library then Get updates. See Updating and Update.My short code does not work
My short code does not work
floe receive then reports code "olive-tiger-castle" not found or expired (codes expire after 10 minutes), quoting the code you typed. Ask the sender to start a new session for a fresh code.Two nearby messages mean something else:this code is no longer active; ask for a new one: the code resolved, but nobody is sharing on it. The sender finished or quit, and codes are single use.room is full (someone else may already be receiving): someone else is already receiving on that code. A room holds exactly two peers.
Desktop app
Test says the realtime connection was refused
Test says the realtime connection was refused
/ws is not reaching it. That is almost always a reverse proxy that forwards ordinary requests without forwarding the upgrade. See Run Floe Behind One Domain.Test says the API answered with HTTP 404
Test says the API answered with HTTP 404
/api/ is not being forwarded. Fix it before you use the server, because nothing else reports this failure: relay credentials fall back to public STUN and the short code silently fails to register, so you get a share link with no code and no error. See Run Floe Behind One Domain.Test says this may be the web app rather than the signaling server
Test says this may be the web app rather than the signaling server
http://localhost:3000 produces this and http://localhost:3001 is what you want. The Server address field always wants the signaling server. See Server for what each Test result means.Test never follows redirects, so a captive portal or a catch-all rewrite cannot pass itself off as a healthy server.Desktop transfers are capped at 2 GB
Desktop transfers are capped at 2 GB
Self-hosting
The browser cannot connect to my signaling server
The browser cannot connect to my signaling server
NEXT_PUBLIC_SOCKET_URL in .env and recreate the container. No rebuild is needed, because the client reads its server address at runtime:SOCKET_URL, which is the name the running client actually reads. If you run the client without Compose, set SOCKET_URL on the client process. Setting NEXT_PUBLIC_SOCKET_URL on an already-built client does nothing, because Next inlines that name at build time.socketUrl means the browser will use its own origin, which is correct only when both services sit behind one reverse proxy. Otherwise confirm the URL is reachable from the end user’s browser: http://localhost:3001 only works when the browser runs on the same machine as the server. See how the client finds the server.Browser requests are blocked by CORS
Browser requests are blocked by CORS
CLIENT_URL to your client’s public origin (for example https://app.your-domain.com), matching scheme and host exactly, with no trailing slash. It joins the allow-list alongside http://localhost:3000 and the floe.one origins, which are always permitted.A rejected origin does not come back as a recognizable CORS error. The server answers HTTP 500 with {"error":"Internal server error"} and logs the stack, while the browser reports a generic CORS failure. If you see that pairing, check CLIENT_URL first. See Production Deployment.I am being rate limited (429 or Rate limit exceeded)
I am being rate limited (429 or Rate limit exceeded)
MAX_CONNECTIONS_PER_IP), 20 TURN credential requests (MAX_TURN_REQUESTS_PER_IP), 60 short-code requests (MAX_CODE_REQUESTS_PER_IP), and 60 global-stats reports. The three HTTP limiters answer 429 with Too many requests, or Too many reports for stats. The connection limiter is not HTTP: it refuses the Socket.IO handshake and closes the WebSocket with the reason Rate limit exceeded. In the browser that surfaces as “Too many refreshes. Reconnecting”.A 503 Server busy, try again shortly from POST /api/code is a different guard. It fires once MAX_ACTIVE_CODES (default 10000) codes are live at once, regardless of source IP.Behind a reverse proxy, set TRUSTED_PROXY_COUNT to the number of proxy hops so the server reads real client IPs instead of the proxy IP. The server defaults to 1, but the Compose stack publishes ports directly and passes 0, so a Compose deployment behind a proxy has to set it explicitly. See Configuration.The TURN relay is not working
The TURN relay is not working
CLOUDFLARE_TURN_KEY_ID and CLOUDFLARE_TURN_KEY_API_TOKEN are set in .env, then run curl http://localhost:3001/api/turn-credentials. A working setup returns turn.cloudflare.com entries with a username and credential. If it returns STUN servers only, one of the two variables is missing or the API token is invalid (roll it in the Cloudflare dashboard under Realtime, then TURN Server).Self-hosted coturn: the bundled coturn service uses host networking, so it runs on a Linux host with a public IP, a domain, and TLS certificates. On macOS or Windows with Docker Desktop, run coturn separately or on a Linux VM. Confirm that TURN_SECRET and TURN_DOMAIN in .env match coturn’s static-auth-secret and realm, then start the stack with docker compose --profile turn up -d.If coturn logs Default realm: localdomain, it is running on built-in defaults with no auth secret and relaying will silently fail. That happens when coturn/turnserver.conf did not exist before the first docker compose up, so Docker created a directory at that path. Run rmdir coturn/turnserver.conf first, because copying a file onto a directory would succeed and write it inside, then fetch the example config and restart. See TURN Relay.