{"record":{"id":"3ad0b4300a1de726","repo":"AlexxIT/go2rtc","slug":"hass-no-token","errorCode":null,"errorMessage":"hass: no token","messagePattern":"hass: no token","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/hass/client.go","lineNumber":40,"sourceCode":"\tquery := u.Query()\n\n\tentityID := query.Get(\"entity_id\")\n\tif entityID == \"\" {\n\t\treturn nil, errors.New(\"hass: no entity_id\")\n\t}\n\n\tvar uri, token string\n\n\tif u.Host == \"supervisor\" {\n\t\turi = \"ws://supervisor/core/websocket\"\n\t\ttoken = SupervisorToken()\n\t} else {\n\t\turi = \"ws://\" + u.Host + \"/api/websocket\"\n\t\ttoken = query.Get(\"token\")\n\t}\n\n\tif token == \"\" {\n\t\treturn nil, errors.New(\"hass: no token\")\n\t}\n\n\t// 1. Check connection to Hass\n\thassAPI, err := NewAPI(uri, token)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tdefer hassAPI.Close()\n\n\t// 2. Create WebRTC client\n\trtcAPI, err := webrtc.NewAPI()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tconf := pion.Configuration{}\n\tpc, err := rtcAPI.NewPeerConnection(conf)","sourceCodeStart":22,"sourceCodeEnd":58,"githubUrl":"https://github.com/AlexxIT/go2rtc/blob/c245815e75e2a5fd60b4290f12bfc04e55a984d3/pkg/hass/client.go#L22-L58","documentation":"For a direct (non-supervisor) Home Assistant connection, NewClient reads the long-lived access token from the token query parameter and requires it for websocket authentication. An empty token aborts construction with this error before NewAPI is called.","triggerScenarios":"Calling hass.NewClient with a non-supervisor URL (host != 'supervisor') whose query string lacks a token parameter or has token= empty. Note: when host is 'supervisor' the token is obtained from SUPERVISOR_TOKEN env instead, so this error only applies to direct connections.","commonSituations":"Running outside the HA Supervisor add-on environment while still omitting the token; using a URL copied from supervisor docs; token env var not expanded into the URL; long-lived access token not created in HA profile settings.","solutions":["Create a long-lived access token in Home Assistant (Profile -> Security -> Long-Lived Access Tokens) and append &token=<TOKEN> to the URL","If running inside a Supervisor add-on, use the URL host 'supervisor' so the SUPERVISOR_TOKEN env is used instead","Check that your config/env expansion actually injects the token value into the query string","Verify the parameter name is exactly token"],"exampleFix":"// before\nclient, err := hass.NewClient(\"ws://ha.local:8123/api/websocket?entity_id=camera.front\")\n// after\nclient, err := hass.NewClient(\"ws://ha.local:8123/api/websocket?entity_id=camera.front&token=\" + longLivedToken)","handlingStrategy":"validation","validationCode":"u, _ := url.Parse(rawURL)\nif u != nil && u.Host != \"supervisor\" && u.Query().Get(\"token\") == \"\" && os.Getenv(\"SUPERVISOR_TOKEN\") == \"\" {\n    return errors.New(\"direct HA connection requires a long-lived access token in the URL\")\n}","typeGuard":"func hasToken(rawURL string) bool {\n    u, err := url.Parse(rawURL)\n    return err == nil && (u.Host == \"supervisor\" || u.Query().Get(\"token\") != \"\")\n}","tryCatchPattern":"client, err := hass.NewClient(rawURL)\nif err != nil {\n    if strings.Contains(err.Error(), \"no token\") {\n        return fmt.Errorf(\"missing Home Assistant access token: %w\", err)\n    }\n    return err\n}","preventionTips":["Create and rotate long-lived access tokens in the HA user profile","Inject the token from an env var/secret, never hardcode it","If running as a Supervisor add-on, use host 'supervisor' so SUPERVISOR_TOKEN is used"],"tags":["home-assistant","authentication","token","client-init"],"backgroundTag":"missing-api-key","analyzedSha":"c245815e75e2a5fd60b4290f12bfc04e55a984d3","analyzedAt":"2026-09-07T11:47:02.965Z","contentChangedAt":"2026-09-07T11:47:02.965Z","schemaVersion":2},"datasetVersion":"2026-09-16T04:17:20.429Z"}