# Buggy code
def transform(self, node):
    # type: (nodes.Node) -> None
    """Transform a single field list *node*."""
    typemap = self.typemap

    entries = []
    groupindices = {}  # type: Dict[unicode, int]
    types = {}  # type: Dict[unicode, Dict]

    # step 1: traverse all fields and collect field types and content
    for field in node:
        fieldname, fieldbody = field
        try:
            # split into field type and argument
            fieldtype, fieldarg = fieldname.astext().split(None, 1)
        except ValueError:
            # maybe an argument-less field type?
            fieldtype, fieldarg = fieldname.astext(), ""
        typedesc, is_typefield = typemap.get(fieldtype, (None, None))

        # collect the content, trying not to keep unnecessary paragraphs
        if _is_single_paragraph(fieldbody):
            content = fieldbody.children[0].children
        else:
            content = fieldbody.children

        # sort out unknown fields
        if typedesc is None or typedesc.has_arg != bool(fieldarg):
            # either the field name is unknown, or the argument doesn't
            # match the spec; capitalize field name and be done with it
            new_fieldname = fieldtype[0:1].upper() + fieldtype[1:]
            if fieldarg:
                new_fieldname += " " + fieldarg
            fieldname[0] = nodes.Text(new_fieldname)
            entries.append(field)

            # but if this has a type then we can at least link it
            if (
                typedesc
                and is_typefield
                and content
                and len(content) == 1
                and isinstance(content[0], nodes.Text)
            ):
                target = content[0].astext()
                xrefs = typedesc.make_xrefs(
                    typedesc.typerolename,
                    self.directive.domain,
                    target,
                    contnode=content[0],
                )
                if _is_single_paragraph(fieldbody):
                    fieldbody.children[0].clear()
                    fieldbody.children[0].extend(xrefs)
                else:
                    fieldbody.clear()
                    fieldbody.extend(xrefs)

            continue

        typename = typedesc.name

        # if the field specifies a type, put it in the types collection
        if is_typefield:
            # filter out only inline nodes; others will result in invalid
            # markup being written out
            content = [
                n
                for n in content
                if isinstance(n, nodes.Inline) or isinstance(n, nodes.Text)
            ]
            if content:
                types.setdefault(typename, {})[fieldarg] = content
            continue

        # also support syntax like ``:param type name:``
        if typedesc.is_typed:
            try:
                argtype, argname = fieldarg.split(None, 1)
            except ValueError:
                pass
            else:
                types.setdefault(typename, {})[argname] = [nodes.Text(argtype)]
                fieldarg = argname

        translatable_content = nodes.inline(fieldbody.rawsource, translatable=True)
        translatable_content.document = fieldbody.parent.document
        translatable_content.source = fieldbody.parent.source
        translatable_content.line = fieldbody.parent.line
        translatable_content += content

        # grouped entries need to be collected in one entry, while others
        # get one entry per field
        if typedesc.is_grouped:
            if typename in groupindices:
                group = entries[groupindices[typename]]
            else:
                groupindices[typename] = len(entries)
                group = [typedesc, []]
                entries.append(group)
            entry = typedesc.make_entry(fieldarg, [translatable_content])
            group[1].append(entry)
        else:
            entry = typedesc.make_entry(fieldarg, [translatable_content])
            entries.append([typedesc, entry])

    # step 2: all entries are collected, construct the new field list
    new_list = nodes.field_list()
    for entry in entries:
        if isinstance(entry, nodes.field):
            # pass-through old field
            new_list += entry
        else:
            fieldtype, content = entry
            fieldtypes = types.get(fieldtype.name, {})
            env = self.directive.state.document.settings.env
            new_list += fieldtype.make_field(
                fieldtypes, self.directive.domain, content, env=env
            )

    node.replace_self(new_list)


# Traceback (TypeError)
# Sphinx version: 1.8.0
# Python version: 3.7.0 (CPython)
# Docutils version: 0.14
# Jinja2 version: 2.10
# Last messages:
#   writing output... [ 59%] someclass
#
# Loaded extensions:
#   sphinx.ext.mathjax (1.8.0) from /.venv/lib/python3.7/site-packages/sphinx/ext/mathjax.py
#   alabaster (0.7.11) from /.venv/lib/python3.7/site-packages/alabaster/__init__.py
#   sphinx.ext.autodoc (1.8.0) from /.venv/lib/python3.7/site-packages/sphinx/ext/autodoc/__init__.py
#   sphinx.ext.napoleon (1.8.0) from /.venv/lib/python3.7/site-packages/sphinx/ext/napoleon/__init__.py
Traceback (most recent call last):
File "/.venv/lib/python3.7/site-packages/sphinx/cmd/build.py", line 304, in build_main
app.build(args.force_all, filenames)
File "/.venv/lib/python3.7/site-packages/sphinx/application.py", line 341, in build
self.builder.build_update()
File "/.venv/lib/python3.7/site-packages/sphinx/builders/__init__.py", line 347, in build_update
len(to_build))
File "/.venv/lib/python3.7/site-packages/sphinx/builders/__init__.py", line 412, in build
self.write(docnames, list(updated_docnames), method)
File "/.venv/lib/python3.7/site-packages/sphinx/builders/__init__.py", line 593, in write
self._write_serial(sorted(docnames))
File "/.venv/lib/python3.7/site-packages/sphinx/builders/__init__.py", line 604, in _write_serial
self.write_doc(docname, doctree)
File "/.venv/lib/python3.7/site-packages/sphinx/builders/html.py", line 730, in write_doc
self.docwriter.write(doctree, destination)
File "/.venv/lib/python3.7/site-packages/docutils/writers/__init__.py", line 80, in write
self.translate()
File "/.venv/lib/python3.7/site-packages/sphinx/writers/html.py", line 58, in translate
self.document.walkabout(visitor)
File "/.venv/lib/python3.7/site-packages/docutils/nodes.py", line 174, in walkabout
if child.walkabout(visitor):
File "/.venv/lib/python3.7/site-packages/docutils/nodes.py", line 174, in walkabout
if child.walkabout(visitor):
File "/.venv/lib/python3.7/site-packages/docutils/nodes.py", line 174, in walkabout
if child.walkabout(visitor):
[Previous line repeated 4 more times]
File "/.venv/lib/python3.7/site-packages/docutils/nodes.py", line 166, in walkabout
visitor.dispatch_visit(self)
File "/.venv/lib/python3.7/site-packages/docutils/nodes.py", line 1882, in dispatch_visit
return method(node)
File "/.venv/lib/python3.7/site-packages/docutils/writers/html4css1/__init__.py", line 402, in visit_field_body
self.set_class_on_child(node, 'first', 0)
File "/.venv/lib/python3.7/site-packages/docutils/writers/_html_base.py", line 399, in set_class_on_child
child['classes'].append(class_)
TypeError: string indices must be integers

# Fixed code
def transform(self, node):
    # type: (nodes.Node) -> None
    """Transform a single field list *node*."""
    typemap = self.typemap

    entries = []
    groupindices = {}  # type: Dict[unicode, int]
    types = {}  # type: Dict[unicode, Dict]

    # step 1: traverse all fields and collect field types and content
    for field in node:
        fieldname, fieldbody = field
        try:
            # split into field type and argument
            fieldtype, fieldarg = fieldname.astext().split(None, 1)
        except ValueError:
            # maybe an argument-less field type?
            fieldtype, fieldarg = fieldname.astext(), ""
        typedesc, is_typefield = typemap.get(fieldtype, (None, None))

        # collect the content, trying not to keep unnecessary paragraphs
        if _is_single_paragraph(fieldbody):
            content = fieldbody.children[0].children
        else:
            content = fieldbody.children

        # sort out unknown fields
        if typedesc is None or typedesc.has_arg != bool(fieldarg):
            # either the field name is unknown, or the argument doesn't
            # match the spec; capitalize field name and be done with it
            new_fieldname = fieldtype[0:1].upper() + fieldtype[1:]
            if fieldarg:
                new_fieldname += " " + fieldarg
            fieldname[0] = nodes.Text(new_fieldname)
            entries.append(field)

            # but if this has a type then we can at least link it
            if (
                typedesc
                and is_typefield
                and content
                and len(content) == 1
                and isinstance(content[0], nodes.Text)
            ):
                target = content[0].astext()
                xrefs = typedesc.make_xrefs(
                    typedesc.typerolename,
                    self.directive.domain,
                    target,
                    contnode=content[0],
                )
                if _is_single_paragraph(fieldbody):
                    fieldbody.children[0].clear()
                    fieldbody.children[0].extend(xrefs)
                else:
                    fieldbody.clear()
                    fieldbody += nodes.paragraph()
                    fieldbody[0].extend(xrefs)

            continue

        typename = typedesc.name

        # if the field specifies a type, put it in the types collection
        if is_typefield:
            # filter out only inline nodes; others will result in invalid
            # markup being written out
            content = [
                n
                for n in content
                if isinstance(n, nodes.Inline) or isinstance(n, nodes.Text)
            ]
            if content:
                types.setdefault(typename, {})[fieldarg] = content
            continue

        # also support syntax like ``:param type name:``
        if typedesc.is_typed:
            try:
                argtype, argname = fieldarg.split(None, 1)
            except ValueError:
                pass
            else:
                types.setdefault(typename, {})[argname] = [nodes.Text(argtype)]
                fieldarg = argname

        translatable_content = nodes.inline(fieldbody.rawsource, translatable=True)
        translatable_content.document = fieldbody.parent.document
        translatable_content.source = fieldbody.parent.source
        translatable_content.line = fieldbody.parent.line
        translatable_content += content

        # grouped entries need to be collected in one entry, while others
        # get one entry per field
        if typedesc.is_grouped:
            if typename in groupindices:
                group = entries[groupindices[typename]]
            else:
                groupindices[typename] = len(entries)
                group = [typedesc, []]
                entries.append(group)
            entry = typedesc.make_entry(fieldarg, [translatable_content])
            group[1].append(entry)
        else:
            entry = typedesc.make_entry(fieldarg, [translatable_content])
            entries.append([typedesc, entry])

    # step 2: all entries are collected, construct the new field list
    new_list = nodes.field_list()
    for entry in entries:
        if isinstance(entry, nodes.field):
            # pass-through old field
            new_list += entry
        else:
            fieldtype, content = entry
            fieldtypes = types.get(fieldtype.name, {})
            env = self.directive.state.document.settings.env
            new_list += fieldtype.make_field(
                fieldtypes, self.directive.domain, content, env=env
            )

    node.replace_self(new_list)