marinakr
NervesHubLink + Shared Secret on NervesCloud: WS upgrade 401 (TLS OK) on fresh app (RPi 5)
Context
I’m following the official tutorial to bring up a minimal Nerves app and connect it to NervesCloud using Shared Secret auth (no Phoenix, no extras). The device boots fine and has network, but the NervesHubLink fails the WebSocket upgrade with 401 even though TLS handshake succeeds.
Environment
- Device: Raspberry Pi 5 (target
rpi5) - Nerves:
1.11.3 - nerves_hub_link:
2.7.3 - VintageNet:
0.13.7 - Host CLI:
nh config set uri "https://manage.nervescloud.com/"nh user auth- Org:
***, Product:my_pi(empty list of devices so far)
What I did (repro)
- New project per tutorial (minimal app, no Phoenix).
target.exs:
config :nerves_hub_link,
host: "devices.nervescloud.com",
remote_iex: true,
shared_secret: [
product_key: "NHP_...REDACTED...", # freshly rotated in UI
product_secret: "...REDACTED..."
]
- Built for
MIX_TARGET=rpi5, burned, booted. - SSH device console:
Nerves.Runtime.serial_number()
"9e5**********" # <- non-empty
:application.get_all_env(:nerves_hub_link)
[
host: "devices.nervescloud.com",
shared_secret: [
product_key: "nhp_............******....",
product_secret: "............******...."
],
remote_iex: true,
fwup_public_keys: []
]
iex(8)> :ssl.connect('devices.nervescloud.com', 443,
...(8)> [verify: :verify_peer, cacerts: :public_key.cacerts_get()], 5000)
{:ok,
{:sslsocket, {:gen_tcp, #Port<0.196>, :tls_connection, :undefined},
[#PID<0.1633.0>, #PID<0.1632.0>]}}
Application.get_env(:nerves_hub_link, :host)
"devices.nervescloud.com"
Error reapeted:
[NervesHubLink] error: {:error, {:upgrade_failure,
%{reason: %Mint.WebSocket.UpgradeFailureError{
status_code: 401,
headers: [
{"date","Thu, 14 Aug 2025 14:11:08 GMT"},
{"content-length","0"},
{"cache-control","max-age=0, private, must-revalidate"}]},
status_code: 401}}}
:alarm_handler: {:set, {NervesHubLink.Disconnected, [...]}}
I did setup secret keys few times, it is valid
The issue is in something else, I cant figure out it what
Does anyone have a clue what it can be?
Most Liked
joshknz
Hey Marina
Thank you for sharing the full device serial number.
I’ve found error messages in our logs which confirm the case of a device with that id already existing in our system (device identifiers are unique across the platform).
I’ve also checked our DB and see that a device with that identifier is associated with a product and org. Could you DM me the name of the Org and Product the device was previously connected to?
Thanks
Josh
joshknz
Thanks for the extra info @marinakr
I think the core of the issue is that Devices are initially soft deleted (recoverable) but need to be ‘destroyed’ after soft deleted.
Or you need to ‘move’ devices from one Product to another, which can be done on the Device list page.
None the less, this is an improvement we need to make on our end.
I’ll get the stuck devices removed ready for you to try again in the morning.
Popular in Questions
Other popular topics
Categories:
Sub Categories:
Forums
Popular Tags
- #ecto
- #liveview
- #troubleshooting
- #learning-elixir
- #deployment
- #library
- #erlang
- #testing
- #genserver
- #mix
- #absinthe
- #remote-other
- #otp
- #plug
- #how-to-question
- #macros
- #postgres
- #channels
- #elixirconf
- #exunit
- #discussion
- #code-sync
- #javascript
- #podcasts
- #onsite
- #dialyzer
- #docker
- #authentication
- #umbrella
- #full-time-contract
- #podcasts-by-brainlid
- #ecto-query
- #elixir-ls
- #phoenix_html
- #iex
- #blog-post
- #graphql
- #genstage
- #ai
- #websockets
- #supervisor
- #advent-of-code
- #elixirconf-us
- #distillery
- #processes
- #forms
- #api
- #metaprogramming
- #security
- #performance









