fyne-io/fyne · error

unhandled token type: %T %+v

Error message

unhandled token type: %T %+v

What it means

Thrown by the Android binary-XML (AXML) compiler in fyne's vendored mobile tool. When 'fyne package -os android' compiles AndroidManifest.xml, binres walks encoding/xml tokens: it handles StartElement, EndElement and CharData, and discards Comment/ProcInst. Any other token type - in practice an xml.Directive such as '<!DOCTYPE ...>' - reaches the default branch and panics with the token's Go type and value.

Source

Thrown at cmd/fyne/internal/mobile/binres/binres.go:588

		}
		n := len(bx.stack)
		var el *Element
		el, bx.stack = bx.stack[n-1], bx.stack[:n-1]
		if el.end != nil {
			return fmt.Errorf("element end already exists")
		}
		el.end = &ElementEnd{
			NodeHeader: NodeHeader{
				LineNumber: uint32(line),
				Comment:    NoEntry,
			},
			NS:   el.NS,
			Name: el.Name,
		}
	case xml.Comment, xml.ProcInst:
		// discard
	default:
		panic(fmt.Errorf("unhandled token type: %T %+v", tkn, tkn))
	}
	return nil
}

// addAttributes encodes the attributes of tkn and adds them to el.
// Any attributes which were not already present in Pool are added to it.
func addAttributes(tkn xml.StartElement, bx *XML, line int, pool *Pool, el *Element, tbl *Table) error {
	for _, attr := range tkn.Attr {
		if (attr.Name.Space == "xmlns" && attr.Name.Local == "tools") || attr.Name.Space == toolsSchema {
			continue // TODO can tbl be queried for schemas to determine validity instead?
		}

		if attr.Name.Space == "xmlns" && attr.Name.Local == "android" {
			if bx.Namespace != nil {
				return fmt.Errorf("multiple declarations of xmlns:android encountered")
			}
			bx.Namespace = &Namespace{
				NodeHeader: NodeHeader{

View on GitHub (pinned to 8860ee95c3)

Solutions

  1. Remove the '<!DOCTYPE ...>' (or any other '<!...>') directive from AndroidManifest.xml - Android packaging does not need it
  2. Re-serialize the manifest with xmllint or an editor so no directive tokens remain, then re-run fyne package
  3. Upgrade fyne to a release that tolerates xml.Directive, or patch the default case in binres.go to discard xml.Directive like xml.Comment

Example fix

// before (AndroidManifest.xml)
<!DOCTYPE manifest PUBLIC "-//Android//DTD Android 3.0//EN" "http://schemas.android.com/apk/res/android">
<manifest ...>

// after
<manifest ...>
Defensive patterns

Strategy: validation

Validate before calling

// Pre-flight: reject manifests containing XML directives before packaging.
dec := xml.NewDecoder(manifestFile)
for {
    tkn, err := dec.Token()
    if err == io.EOF { break }
    if err != nil { return err }
    if _, ok := tkn.(xml.Directive); ok {
        return fmt.Errorf("AndroidManifest.xml contains an XML directive; remove it before packaging")
    }
}

Prevention

When it happens

Trigger: Running 'fyne package -os android' (or calling binres XML build) against a custom AndroidManifest.xml that contains an XML directive: a '<!DOCTYPE manifest ...>' declaration or '<!ELEMENT>'/'<!ENTITY>' lines produced by an XML editor or copied from an Android Studio project.

Common situations: Custom manifests pasted from tutorials or other projects that carry a DOCTYPE; manifests processed by XML tooling that emits directives; template files reused across projects.

Related errors


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