OpenNHP/opennhp · error

length is negative

Error message

length %d is negative

What it means

encodeMetadataLength serializes a metadata chunk length into a 2-byte, 7-bit-per-byte encoding with a continuation flag for ztdo metadata. The library refuses values outside [0, MetadataChunkMaxSize] because negative lengths cannot be encoded and larger values overflow the encoded format. This guard prevents silent truncation or corrupted metadata frames.

Solutions

  1. Inspect the caller (SetMetadata) and fix the length arithmetic so it never produces a negative value before calling SetMetadata
  2. Clamp or validate the metadata payload length before calling SetMetadata, e.g. if l < 0 { return fmt.Errorf("invalid metadata length %d", l) }
  3. Verify MetadataChunkMaxSize handling is separate from the negative check; both branches return the partial result and must be handled by the caller

Example fix

// before
metaLen := len(payload) - headerSize
packet.SetMetadata(key, payload[:metaLen])
// after
metaLen := len(payload) - headerSize
if metaLen < 0 {
    return fmt.Errorf("payload too short: %d bytes after %d-byte header", len(payload), headerSize)
}
packet.SetMetadata(key, payload[:metaLen])
Defensive patterns

Strategy: validation

Validate before calling

meta := []byte(value)
if len(meta) < 0 || len(meta) > ztdo.MetadataChunkMaxSize {
    return fmt.Errorf("metadata length %d out of [0,%d]", len(meta), ztdo.MetadataChunkMaxSize)
}

Type guard

func validMetaLen(n int) bool { return n >= 0 && n <= 4096 /* MetadataChunkMaxSize */ }

Try / catch

if err := pkt.SetMetadata(k, v); err != nil {
    if strings.Contains(err.Error(), "is negative") || strings.Contains(err.Error(), "exceeds maximum") {
        return fmt.Errorf("bad metadata %q: %w", k, err)
    }
    return err
}

Prevention

When it happens

Trigger: SetMetadata (or an anonymous helper it calls) is invoked with a metadata value whose serialized length is negative, which in practice means a length computation underflowed (e.g. len(x) minus an offset larger than the slice) before reaching encodeMetadataLength.

Common situations: A caller computed the metadata length from a slicing expression like len(data)-headerLen where the header was bigger than the data; a custom metadata encoder passed a signed int straight through with a bad arithmetic result; fuzzed or hostile input produced a negative computed size.

Understand the failure class

Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.

Related errors


AI-assisted analysis of OpenNHP/opennhp@6e04ca5ff0 (2026-09-07). Data as JSON: /api/errors/99a6087156dee487. Report an issue: GitHub.

Appendix: source

Thrown at nhp/core/ztdo/ztdo.go:664

		}

		rvalue.Set(newArray)

	} else {
		panic("not support")
	}
}

// encodeMetadataLength encodes a length continuation bit into the MSB of metadata length
func encodeMetadataLength(length int, continuation bool) ([2]byte, error) {
	var result [2]byte

	if length > MetadataChunkMaxSize {
		return result, fmt.Errorf("length %d exceeds maximum encoded value (%d)", length, MetadataChunkMaxSize)
	}

	if length < 0 {
		return result, fmt.Errorf("length %d is negative", length)
	}

	//nolint:gosec // G602: result is [2]byte array, indices 0 and 1 are always valid
	result[0] = byte((length >> 8) & 0x7F)
	if continuation {
		result[0] |= 0x80
	}
	result[1] = byte(length & 0xFF)

	if littleEndian {
		result[0], result[1] = result[1], result[0]
	}

	return result, nil
}

// preprocessContinuation decodes a length continuation bit from the MSB of metadata length
func preprocessContinuation(encoded []byte) (continuation bool) {

View on GitHub (pinned to 6e04ca5ff0)