AlexxIT/go2rtc · error
onvif: wrong subtype
Error message
onvif: wrong subtype
What it means
GetURI in pkg/onvif/client.go lets callers select an ONVIF media profile by numeric index (subtype). When the token in the URI is a non-negative integer, the client fetches GetProfilesTokens and treats the number as an index into that list; if the index is >= the number of profiles the device exposes, it returns errors.New("onvif: wrong subtype").
Solutions
- Use subtype 0 (or the lowest valid index) and confirm how many profiles the camera actually has via GetProfilesTokens
- Enumerate the device's profiles with GetProfile/GetProfilesTokens and pick the profile token directly instead of a numeric subtype
- Check 0-based vs 1-based indexing expectations against the library's implementation (i indexes into the tokens slice directly)
- Update the camera firmware or add/reconfigure media profiles on the device if you genuinely need a second stream
- Log len(tokens) at startup and fail fast with a clear message when the configured subtype exceeds it
Example fix
// before
uri, err := cam.GetURI("onvif://...?subtype=1") // camera has only 1 profile
// after
tokens, err := cam.GetProfilesTokens()
if err != nil { return err }
sub := 1
if sub >= len(tokens) { sub = 0 } // fall back to the only profile
uri, err = cam.GetURI(fmt.Sprintf("onvif://...?subtype=%d", sub)) Defensive patterns
Strategy: validation
Validate before calling
tokens, err := c.GetProfilesTokens()
if err != nil { return err }
if subtype >= len(tokens) {
return fmt.Errorf("subtype %d out of range: device has %d profile(s)", subtype, len(tokens))
} Type guard
func validSubtype(subtype int, tokenCount int) bool {
return subtype >= 0 && subtype < tokenCount
} Try / catch
uri, err := cam.GetURI(u)
if err != nil {
if err.Error() == "onvif: wrong subtype" {
return cam.GetURI(strings.Replace(u, "subtype=1", "subtype=0", 1))
}
return err
} Prevention
- Discover profile count via GetProfilesTokens at startup and clamp the configured subtype
- Don't copy stream subtypes between camera models — each device has its own profile table
- Confirm 0-based indexing used by this library when mapping subtype numbers
- Persist the actual profile token rather than the numeric subtype for long-lived configs
When it happens
Trigger: Calling GetURI with a stream subtype like 1, 2, 3 ... on a camera whose GetProfiles response contains fewer profiles — e.g. requesting subtype 1 on a single-profile camera, or a higher index on a camera with only 2 profiles.
Common situations: Reusing a URL template that worked on one camera model on another camera with fewer profiles; assuming 0-based vs 1-based indexing mismatches; firmware update that reduced the number of profiles; a camera whose media profiles only include one main stream.
Related errors
- onvif: unsupported service
- onvif: wrong response
- ffmpeg: unsupported params:
- wrong response:
- wrong auth response
AI-assisted analysis of AlexxIT/go2rtc@c245815e75 (2026-09-07).
Data as JSON: /api/errors/e912448bed45c4c6.
Report an issue: GitHub.
Appendix: source
Thrown at pkg/onvif/client.go:62
s = FindTagValue(b, "Imaging.+?XAddr")
client.imaginURL = baseURL + GetPath(s, "/onvif/imaging_service")
return client, nil
}
func (c *Client) GetURI() (string, error) {
query := c.url.Query()
token := query.Get("subtype")
// support empty
if i := atoi(token); i >= 0 {
tokens, err := c.GetProfilesTokens()
if err != nil {
return "", err
}
if i >= len(tokens) {
return "", errors.New("onvif: wrong subtype")
}
token = tokens[i]
}
getUri := c.GetStreamUri
if query.Has("snapshot") {
getUri = c.GetSnapshotUri
}
b, err := getUri(token)
if err != nil {
return "", err
}
rawURL := FindTagValue(b, "Uri")
rawURL = strings.TrimSpace(html.UnescapeString(rawURL))
u, err := url.Parse(rawURL)View on GitHub (pinned to c245815e75)