fyne-io/fyne · error

string lengths over 1<<15 not yet supported, got len %d

Error message

string lengths over 1<<15 not yet supported, got len %d

What it means

The binary resource string-pool encoder writes every string with a UTF-16 length prefix that must fit in 16 bits. Strings whose Go byte length has bits above bit 15 set (len(x)>>16 > 0) cannot be represented, so the encoder panics citing the 1<<15 supported limit. The pool holds every string compiled into the APK resources - manifest values, string resources, etc.

Source

Thrown at cmd/fyne/internal/mobile/binres/pool.go:190

}

// MarshalBinary outputs the binary format from a given pool
func (pl *Pool) MarshalBinary() ([]byte, error) {
	if pl.IsUTF8() {
		return nil, fmt.Errorf("encode utf8 not supported")
	}

	var (
		hdrlen = 28
		// indices of string indices
		iis    = make([]uint32, len(pl.strings))
		iislen = len(iis) * 4
		// utf16 encoded strings concatenated together
		strs []uint16
	)
	for i, x := range pl.strings {
		if len(x)>>16 > 0 {
			panic(fmt.Errorf("string lengths over 1<<15 not yet supported, got len %d", len(x)))
		}
		p := utf16.Encode([]rune(x))
		if len(p) == 0 {
			strs = append(strs, 0x0000, 0x0000)
		} else {
			strs = append(strs, uint16(len(p))) // string length (implicitly includes zero terminator to follow)
			strs = append(strs, p...)
			strs = append(strs, 0) // zero terminated
		}
		// indices start at zero
		if i+1 != len(iis) {
			iis[i+1] = uint32(len(strs) * 2) // utf16 byte index
		}
	}

	// check strings is 4-byte aligned, pad with zeros if not.
	for x := (len(strs) * 2) % 4; x != 0; x -= 2 {
		strs = append(strs, 0x0000)

View on GitHub (pinned to 8860ee95c3)

Solutions

  1. Split the oversized string into multiple shorter resources and join them at runtime
  2. Move the payload out of resources into a bundled asset file loaded with fyne storage or os.ReadFile
  3. Shorten generated manifest fields (descriptions, URI lists) to well below 32Ki characters

Example fix

<!-- before (strings.xml) -->
<string name="payload">AAAA...65KB-of-base64...==</string>

<!-- after -->
<string name="payload_1">first 16Ki chars</string>
<string name="payload_2">remaining chars</string>
Defensive patterns

Strategy: validation

Validate before calling

// Pre-flight: flag any resource/manifest string that could blow the UTF-16 length prefix.
const maxStringLen = 1 << 15 // conservative: the pool writes a uint16 length
func tooLong(s string) bool { return len([]rune(s)) >= maxStringLen }

for name, val := range stringResources {
    if tooLong(val) { return fmt.Errorf("resource %s exceeds %d chars; split it or move to an asset", name, maxStringLen) }
}

Prevention

When it happens

Trigger: Any single string at or beyond the length limit while packaging for Android: a giant label/description, a huge deep-link or scheme list in AndroidManifest.xml, or one enormous strings.xml entry.

Common situations: Base64 blobs, API keys or certificates pasted into string resources; concatenated locale text generated by scripts; manifests with embedded data payloads.

Related errors


AI-assisted analysis of fyne-io/fyne@8860ee95c3 (2026-08-15). Data as JSON: /api/errors/ad8d680c013ed258. Report an issue: GitHub.