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

  1. Use subtype 0 (or the lowest valid index) and confirm how many profiles the camera actually has via GetProfilesTokens
  2. Enumerate the device's profiles with GetProfile/GetProfilesTokens and pick the profile token directly instead of a numeric subtype
  3. Check 0-based vs 1-based indexing expectations against the library's implementation (i indexes into the tokens slice directly)
  4. Update the camera firmware or add/reconfigure media profiles on the device if you genuinely need a second stream
  5. 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

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


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)