This document lists all errors emitted by the [FIDL compiler](https://fuchsia.dev/fuchsia-src/reference/fidl/language/fidlc.md),
`fidlc`. Error identifiers in this domain are always rendered with the prefix
`fi-` followed by a four digit code, like `fi-0123`.

## fi-0001: Invalid character

The lexer failed to convert a character into a token at
the specified location.

> [!WARNING]
> **Incorrect**

    library test.bad.fi0001;

    type ßar = struct {
        value uint64;
    };

An invalid character should be fixed by substitution or removal.

> [!TIP]
> **Correct**

    library test.good.fi0001;

    type Foo = struct {
        value uint64;
    };

Invalid characters are location dependent. Please refer to the
[FIDL language specification](https://fuchsia.dev/docs/reference/fidl/language/language) to determine
which characters are permitted in each part of the FIDL syntax.

## fi-0002: Unexpected line break

String literals are not allowed to be split across multiple lines:

> [!WARNING]
> **Incorrect**

    library test.bad.fi0002;

    const BAD_STRING string:1 = "Hello
    World";

Instead, use the escape sequence `\n` to represent a line break:

> [!TIP]
> **Correct**

    library test.good.fi0002;

    const GOOD_STRING string:11 = "Hello\nWorld";

## fi-0003: Invalid escape sequence

The lexer encountered an invalid character at the beginning of an
escape sequence.

> [!WARNING]
> **Incorrect**

    library test.bad.fi0003;

    const UNESCAPED_BACKSLASH string:2 = "\ ";
    const BACKSLASH_TYPO string:1 = "\i";
    const CODE_POINT_TYPO string:1 = "\Y1F604";

Substitute a valid character to begin the escape sequence, or remove the
unintended backslash character.

> [!TIP]
> **Correct**

    library test.good.fi0003;

    const ESCAPED_BACKSLASH string:2 = "\\ ";
    const REMOVED_BACKSLASH string:1 = "i";
    const SMALL_CODE_POINT string:3 = "\u{2604}";
    const BIG_CODE_POINT string:4 = "\u{01F604}";

Refer to the [FIDL grammar specification](https://fuchsia.dev/docs/reference/fidl/language/grammar#string-literal)
for valid escape sequences.

## fi-0004: Invalid hex digit

Unicode escapes in string literals must not contain invalid hex digits:

> [!WARNING]
> **Incorrect**

    library test.bad.fi0004;

    const SMILE string = "\u{1G600}";

You must specify a valid [Unicode code point](https://en.wikipedia.org/wiki/Unicode#Codespace_and_Code_Points) in hexadecimal, from 0 to 10FFFF.
Each hex digit must be a number from 0 to 9, a lowercase letter from `a` to `f`,
or an uppercase letter from `A` to `F`. In this case, `G` was a typo for `F`:

> [!TIP]
> **Correct**

    library test.good.fi0004;

    const SMILE string = "\u{1F600}";

## fi-0005

> [!WARNING]
> **Deprecated:** This error code has been retired.

## fi-0006: Expected declaration

This error happens when FIDL expects a declaration and finds something else.
This is often caused by a typo. The valid declarations are: `type`, `alias`,
`const`, `using`, `protocol`, and `service`.

> [!WARNING]
> **Incorrect**

    library test.bad.fi0006;

    cosnt SPELLED_CONST_WRONG string:2 = ":("; // Expected a declaraction (such as const).

To fix this error, check for typos in your top-level declarations and ensure
you're only using features that are supported by FIDL.

> [!TIP]
> **Correct**

    library test.good.fi0006;

    const SPELLED_CONST_RIGHT string:2 = ":)";

## fi-0007: Unexpected token

This error occurs when an unexpected token is encountered during parsing.
Generally speaking, this is the result of a typo:

> [!WARNING]
> **Incorrect**

    library test.bad.fi0007;

    alias MyType = vector<uint8>:<,256,optional>; // Extra leading comma

The fix to this problem is typically to remove the unexpected token, or in some
cases, provide the rest of the missing syntax:

> [!TIP]
> **Correct**

    library test.good.fi0007;

    alias MyType = vector<uint8>:<256, optional>;

## fi-0008: Unexpected token

This error happens whenever the FIDL parser encounters a grammatically invalid
token. This can happen many ways--for example a missing `=` for an enum member,
an extra token such as `library = what.is.that.equals.doing.there`, and so on.

> [!WARNING]
> **Incorrect**

    library test.bad.unexpectedtokenofkind;

    type Numbers = flexible enum {
        ONE; // FIDL enums don't have a default value.
    };

Generally, the fix to this problem will be adding a missing token or removing an
extra one.

> [!TIP]
> **Correct**

    library test.good.fi0008;

    type Numbers = flexible enum {
        ONE = 1;
    };

To avoid this error, do a once over on your `*.fidl` files to make sure they're
grammatically correct.

## fi-0009: Unexpected identifier

This error usually occurs when an identifier is used in an incorrect position:

> [!WARNING]
> **Incorrect**

    using test.bad.fi0009;

Use the correct identifier instead:

> [!TIP]
> **Correct**

    library test.good.fi0009;

## fi-0010: Invalid identifier

An identifier was found which does not meet the requirements for valid
identifiers. FIDL identifiers may contain alphanumerics and underscores
(specifically `A-Z`, `a-z`, `0-9`, and `_`), and additionally each identifier
must begin with a letter and end with either a letter or number.

> [!WARNING]
> **Incorrect**

    library test.bad.fi0010a;

    // Foo_ is not a valid identifier because it ends with '_'.
    type Foo_ = struct {
        value uint64;
    };

To fix this, change the identifier to make sure it contains only valid
characters, starts with a letter, and ends with a letter or number.

> [!TIP]
> **Correct**

    library test.good.fi0010a;

    type Foo = struct {
        value uint64;
    };

This error may also occur if a multi-part (dotted) identifier is passed to an
attribute.

> [!WARNING]
> **Incorrect**

    library test.bad.fi0010b;

    @foo(bar.baz="Bar", zork="Zoom")
    type Empty = struct{};

To fix this, change to use only single-part identifiers in attributes.

> [!TIP]
> **Correct**

    library test.good.fi0010b;

    @foo(bar="Bar", zork="Zoom")
    type Empty = struct {};

> [!NOTE]
> **Note:** This error generally only occurs when an identifier contains all valid characters, just in an invalid order, such as if an otherwise valid identifier starts with a number or underscore, ends with an underscore, or if the argument name for an attribute is a multi-part identifier. If characters which are not valid in an identifier are used, it will result in some other error, such as [fi-0001: Invalid Character](https://fuchsia.dev/fuchsia-src/reference/fidl/language/errcat#fi-0001).

## fi-0011: Invalid library name component

Library names must only contain letters and numbers (`A-Z`, `a-z`, and `0-9`),
and must start with a letter.

> [!WARNING]
> **Incorrect**

    library test.bad.fi0011.name_with_underscores;

To fix this, ensure that all library name components meet the requirements.

> [!TIP]
> **Correct**

    library test.good.fi0011.namewithoutunderscores;

> [!NOTE]
> **Note:** This error generally only occurs when a library name otherwise contains only characters which are valid in a FIDL identifier (`A-Z`, `a-z`, `0-9`, or `_`). If a library name contains other characters, some other error will occur, such as [fi-0001: Invalid Character](https://fuchsia.dev/fuchsia-src/reference/fidl/language/errcat#fi-0001).

## fi-0012: Invalid type layout class

Type declarations must specify a layout known to FIDL:

> [!WARNING]
> **Incorrect**

    library test.bad.fi00012;

    type Foo = invalid {};

The valid layouts are `bits`, `enum`, `struct`, `table`, and `union`:

> [!TIP]
> **Correct**

    library test.good.fi0012;

    type Empty = struct {};

A [layout](https://fuchsia.dev/docs/reference/fidl/language/lexicon#type-terms) is a parameterizable description of a FIDL
type. It refers to a family of would-be types which can receive further
arguments to specify their shape. For example, a `struct` is a kind of layout
which becomes a concrete type when it has specific members defined, while an
`array` is a layout that becomes concrete when given a type to be repeated
sequentially a specified number of times.

Layouts are all built into the FIDL language - there is no means by which users
can specify their own layouts, or create their own generic type templates.

## fi-0013: Invalid wrapped type

This error occurs when the value passed to an enum or bits declaration isn't an
identifier for a type, such as when you instead provide a string value as the
"backing type":

> [!WARNING]
> **Incorrect**

    library test.bad.fi0013;

    type TypeDecl = enum : "int32" {
        FOO = 1;
        BAR = 2;
    };

To fix this error, make sure the backing type for the enum or bits is a type
identifier.

> [!TIP]
> **Correct**

    library test.good.fi0013;

    type TypeDecl = enum : int32 {
        FOO = 1;
        BAR = 2;
    };

> [!NOTE]
> **Note:** If the value provided as the backing type is an identifier but is not the identifier of one of the supported backing types, it will instead cause [fi-0070: Enum Type Must Be Integral Primitive](https://fuchsia.dev/fuchsia-src/reference/fidl/language/errcat#fi-0070).

## fi-0014: Attribute with empty parentheses

This error occurs if an attribute has parentheses but no arguments.

> [!WARNING]
> **Incorrect**

    library test.bad.fi0014;

    @discoverable()
    protocol MyProtocol {};

To fix it, remove the parentheses from attributes with no arguments, or supply
arguments if arguments were intended.

> [!TIP]
> **Correct**

    library test.good.fi0014;

    @discoverable
    protocol MyProtocol {};

FIDL disallows empty argument lists on attributes mostly as a stylistic choice.

## fi-0015: Attribute args must all be named

For clarity, when an attribute has more than one argument, all of the
attribute's arguments must be explicitly named.

This error occurs when an attribute has more than one argument but does not
explicitly provide names for the arguments.

> [!WARNING]
> **Incorrect**

    library test.bad.fi0015;

    @foo("abc", "def")
    type MyStruct = struct {};

To fix it, provides names for all of the arguments using `name=value` syntax.

> [!TIP]
> **Correct**

    library test.good.fi0015;

    @foo(bar="abc", baz="def")
    type MyStruct = struct {};

> [!NOTE]
> **Note:** This does not apply if an attribute has just a single argument.

## fi-0016: Missing ordinal before member

This error occurs when a fields in a union or table is missing an ordinal.

> [!WARNING]
> **Incorrect**

    library test.bad.fi0016a;

    type Foo = table {
        x int64;
    };

> [!WARNING]
> **Incorrect**

    library test.bad.fi0016b;

    type Bar = union {
        foo int64;
        bar vector<uint32>:10;
    };

To fix this error, explicitly specify the ordinals for the table or union:

> [!TIP]
> **Correct**

    library test.good.fi0016;

    type Foo = table {
        1: x int64;
    };

    type Bar = union {
        1: foo int64;
        2: bar vector<uint32>:10;
    };

Unlike structs, tables and unions are designed to allow backwards-compatible
changes to be made to their contents. In order to enable this, a consistent
value, the ordinal, is needed to identify table fields or union variants. To
avoid confusion and make it harder to accidentally change ordinals when changing
a table or union, ordinals must always be specified explicitly.

## fi-0017: Ordinal out of bound

Ordinals for tables and Unions must be valid unsigned 32 bit integers. Negative
ordinals or ordinals greater than 4,294,967,295 will cause this error.

> [!WARNING]
> **Incorrect**

    library test.bad.fi0017a;

    type Foo = table {
      -1: foo string;
    };

> [!WARNING]
> **Incorrect**

    library test.bad.fi0017b;

    type Bar = union {
      -1: foo string;
    };

To fix this error, ensure that all ordinals are in the allowed range.

> [!TIP]
> **Correct**

    library test.good.fi0017;

    type Foo = table {
        1: foo string;
    };

    type Bar = union {
        1: foo string;
    };

> [!NOTE]
> **Note:** Tables are limited to 64 ordinals and are ordinals are required to be dense (sequential starting from 1), so the actual limit for table ordinals is 64. Specifying a negative ordinal or an ordinal larger than 4,294,967,295 will cause this error, fi-0017: Ordinal Out of Bound. Specifying an ordinal between 65 and 4,294,967,295 will cause either [fi-0092: Too Many Table
> Ordinals](https://fuchsia.dev/fuchsia-src/reference/fidl/language/errcat#fi-0092) if there are no missing ordinals or [fi-0100: Ordinals Must
> Be Dense](https://fuchsia.dev/fuchsia-src/reference/fidl/language/errcat#fi-0100) if there are any missing ordinals.

> [!NOTE]
> **Note:** Union ordinals are required to be dense (sequential starting from 1), so specifying large numbers as ordinals is not possible unless you actually have that many variants. If an ordinal larger than 4,294,967,295 is specified, it will cause this error, fi-0017: Ordinal Out of Bound\]. If a large ordinal is specified without the union also having every other ordinal between 1 and that value, it will cause [fi-0100: Ordinals Must Be Dense](https://fuchsia.dev/fuchsia-src/reference/fidl/language/errcat#fi-0100).

## fi-0018: Ordinals must start at 1

Neither `table` nor `union` member ordinal values are allowed to be 0:

> [!WARNING]
> **Incorrect**

    library test.bad.fi0018;

    type Foo = strict union {
        0: foo uint32;
        1: bar uint64;
    };

Instead, numbering should start from 1:

> [!TIP]
> **Correct**

    library test.good.fi0018;

    type Foo = strict union {
        1: foo uint32;
        2: bar uint64;
    };

## fi-0019: Strict bits, enum, or union cannot be empty

A strict bits, enum, or union is not allowed to have zero members:

> [!WARNING]
> **Incorrect**

    library test.bad.fi0019;

    type Numbers = strict enum {};

Instead, there must be at least one member:

> [!TIP]
> **Correct**

    library test.good.fi0019a;

    type Numbers = flexible enum {};

Alternatively, you can mark the declaration `flexible` instead of `strict`:

> [!TIP]
> **Correct**

    library test.good.fi0019b;

    type Numbers = strict enum {
        ONE = 1;
    };

An empty bits, enum, or union carries no information, so it should not normally
be used in an API. However, flexible data types are designed for evolution, so
it makes sense to define a flexible bits or enum that starts out empty, with the
expectation of adding members later on. You should always think carefully about
whether to use `strict` or `flexible` when defining a new data type.

## fi-0020: Invalid protocol member

This error occurs when an item in a protocol is not recognized as a valid
protocol member such as when something in a protocol is not a protocol
composition, one-way method, two-way method, or event.

> [!WARNING]
> **Incorrect**

    library test.bad.fi0020;

    protocol Example {
        NotAMethodOrCompose;
    };

To fix this error, remove the invalid items or convert them to the correct
syntax for the type of protocol item they were intended to be.

> [!TIP]
> **Correct**

    library test.good.fi0020;

    protocol Example {
        AMethod();
    };

> [!NOTE]
> **Note:** FIDL protocols may only contain compose statements, one-way methods, two-way methods, and events. Attempting to place any other kind of declaration directly within a protocol is an error. Declarations for other protocols and named types can be placed outside of the protocol block. Anonymous types for methods and events can be placed inside of the method declaration, but not directly in the protocol body.

## fi-0021

> [!WARNING]
> **Deprecated:** This error code has been retired.

## fi-0022: Cannot attach attribute to identifier

This error occurs when an attribute is placed on the type of a declaration
when that type is an identifier type. For example, placing an attribute after
field name but before the field's type in a struct declaration associates the
attribute with the type of the field rather than with the field itself. If the
type of the field is a preexisting type being referenced by name, additional
attributes cannot be applied to it.

> [!WARNING]
> **Incorrect**

    library test.bad.fi0022;

    type Foo = struct {
        // uint32 is an existing type, extra attributes cannot be added to it just
        // for this field.
        data @foo uint32;
    };

If the intent was to apply an attribute to the field, the attribute should be
moved before the field name.

Attributes can be applied to types where they are declared. This means that if
the type of a struct field or other similar declaration is an anonymous type
rather than an identifier type, attributes can be applied to the type.

> [!TIP]
> **Correct**

    library test.good.fi0022;

    type Foo = struct {
        // The foo attribute is associated with the data1 field, not the uint32
        // type.
        @foo
        data1 uint32;
        // The type of data2 is a newly declared anonymous structure, so that new
        // type can have an attribute applied to it.
        data2 @foo struct {};
    };

## fi-0023: Attribute inside type declaration

With [inline layouts](https://fuchsia.dev/docs/reference/fidl/language/language#inline-layouts),
you can put attributes directly before the layout. However, when declaring a
type at the top level, you cannot:

> [!WARNING]
> **Incorrect**

    library test.bad.fi0023;

    type Foo = @foo struct {};

Instead, you must put attributes before the `type` keyword:

> [!TIP]
> **Correct**

    library test.good.fi0023;

    @foo
    type Foo = struct {};

We enforce this because it would be confusing to allow attributes in two places.

## fi-0024: Doc comment on method parameter list

Method parameter lists cannot carry doc comments:

> [!WARNING]
> **Incorrect**

    library test.bad.fi0024;

    protocol Example {
        Method(/// This is a one-way method.
                struct {
            b bool;
        });
    };

For the [time being](https://fxbug.dev/42062042), place doc comments on the method itself:

> [!TIP]
> **Correct**

    library test.good.fi0024;

    protocol Example {
        /// This is a one-way method.
        Method(struct {
            b bool;
        });
    };

This error will no longer exist once [this bug](https://fxbug.dev/42062042) is resolved. The
error a holdover from the [migration](https://fuchsia.dev/docs/contribute/governance/rfcs/0050_syntax_revamp) to describe method payloads
using FIDL types, rather than parameter lists.

## fi-0025: Imports group must be at top of file

Except for the `library` declaration at the top of the file, there cannot be any
other declarations before the `using` imports for the file, should they exist:

> [!WARNING]
> **Incorrect**

    library test.bad.fi0025;

    alias i16 = int16;
    using dependent;

    type UsesDependent = struct {
        field dependent.Something;
    };

To resolve this error, place all of your `using` imports in a block directly
after the `library` declaration:

> [!TIP]
> **Correct**

    library test.good.fi0025;

    using dependent;

    alias i16 = int16;
    type UsesDependent = struct {
        field dependent.Something;
    };

This rule reflects a primarily aesthetic decision by the FIDL team that
dependencies are easier to read when they are well-grouped and easily located.

## fi-0026: Comment inside doc comment block

Comments should not be placed inside of a doc comment block:

> [!WARNING]
> **Incorrect**

    library test.bad.fi0026;

    /// start
    // middle
    /// end
    type Empty = struct {};

Instead, comments should be placed before or after the doc comment block:

> [!TIP]
> **Correct**

    library test.good.fi0026;

    // some comments above,
    // maybe about the doc comment
    /// A
    /// multiline
    /// comment!
    // another comment, maybe about the struct
    type Empty = struct {};

Generally, comments immediately preceding the doc comment block are the best
place for comments about the doc comment itself.

## fi-0027: Blank lines in doc comment block

There should be no blank lines in a doc comment block:

> [!WARNING]
> **Incorrect**

    library test.bad.fi0027;

    /// start

    /// end
    type Empty = struct {};

Instead, blank lines should only be placed before or after the doc comment
block:

> [!TIP]
> **Correct**

    library test.good.fi0027a;

    /// A doc comment
    type Empty = struct {};

Alternatively, consider omitting the blank lines altogether:

> [!TIP]
> **Correct**

    library test.good.fi0027b;

    /// A doc comment
    type Empty = struct {};

## fi-0028: Doc comment must be followed by a declaration

Doc comments are never allowed to be free-floating, like regular comments:

> [!WARNING]
> **Incorrect**

    library test.bad.fi0028;

    type Empty = struct {};
    /// bad

Doc comments must directly precede FIDL declarations in all circumstances:

> [!TIP]
> **Correct**

    library test.good.fi0028a;

    /// A doc comment
    type Empty = struct {};

FIDL "lowers" doc comments to `@doc` attributes during compilation. In fact, any
comment can be written directly in such a manner if so desired:

    library test.good.fi0028b;

    @doc("An attribute doc comment")
    type Empty = struct {};

Standalone doc comments are non-compilable from a technical perspective, but are
also confusing semantically: what does it mean to "document" nothing? Unlike
regular comments, doc comments get processed into structured documentation, and
thus must be clear about which FIDL construct they are attached to.

## fi-0029: Resource definition must have at least one property

Resource definitions with no properties specified are prohibited:

> [!WARNING]
> **Incorrect**

    library test.bad.resourcedefinitionnoproperties;

    resource_definition SomeResource : uint32 {
      properties {};
    };

Please specify at least one property:

> [!TIP]
> **Correct**

    library test.good.fi0029;

    resource_definition SomeResource : uint32 {
        properties {
            subtype strict enum : uint32 {
                NONE = 0;
            };
        };
    };

This is an error related to FIDL's internal implementation, and thus should only
ever be surfaced to developers working on FIDL's core libraries. End users
should never see this error.

The `resource_definition` declaration it refers to is FIDL's internal means of
defining resources like handles, and is likely to change in the future as part
of the [handle generalization](https://fxbug.dev/42143256) effort.

## fi-0030: Invalid modifier

Each FIDL modifier has a specific set of declarations in which it can be used.
Using the modifier in a prohibited declaration is not allowed:

> [!WARNING]
> **Incorrect**

    library test.bad.fi0030;

    type MyStruct = strict struct {
        i int32;
    };

The best course of action is to remove the offending modifier:

> [!TIP]
> **Correct**

    library test.good.fi0030;

    type MyStruct = struct {
        i int32;
    };

## fi-0031: Only bits and enum can have subtype

Not every FIDL layout can carry a subtype:

> [!WARNING]
> **Incorrect**

    library test.bad.fi0031;

    type Foo = flexible union : uint32 {};

Only `bits` and `enum` layouts are defined over an underlying type.

> [!TIP]
> **Correct**

    library test.good.fi0031;

    type Foo = flexible enum : uint32 {};

The `bits` and `enum` layouts are somewhat unique, in that they are just
constrained subtypings of the integral FIDL primitives. Because of this, it
makes sense for them to specify an underlying type which acts as this subtype.
Conversely, `struct`, `table`, and `union` layouts can be arbitrarily large and
can contain many members, therefore a global, layout-wide subtype does not make
sense.

## fi-0032: Duplicate modifiers disallowed

Specifying the same modifier in a single declaration is prohibited:

> [!WARNING]
> **Incorrect**

    library test.bad.fi0032;

    type MyUnion = strict resource strict union {
        1: foo bool;
    };

Remove the duplicated modifier:

> [!TIP]
> **Correct**

    library test.good.fi0032;

    type MyUnion = resource strict union {
        1: foo bool;
    };

## fi-0033: Conflicting modifiers

Certain modifiers are mutually exclusive of one another and cannot both modify
the same declaration:

> [!WARNING]
> **Incorrect**

    library test.bad.conflictingmodifiers;

    type StrictFlexibleFoo = strict flexible union {
        1: b bool;
    };

    type FlexibleStrictBar = flexible strict union {
        1: b bool;
    };

Only one of the `strict` or `flexible` modifiers may be used on a single
declaration at a time:

> [!TIP]
> **Correct**

    library test.good.fi0033;

    type FlexibleFoo = flexible union {
        1: i int32;
    };

    type StrictBar = strict union {
        1: i int32;
    };

At this time, only the `strict` and `flexible` modifiers are mutually exclusive
in this manner. The `resource` modifier has no reciprocal modifier, and thus has
no such restrictions applied to it.

## fi-0034: Name collision

Two declarations cannot have the same name:

> [!WARNING]
> **Incorrect**

    library test.bad.fi0034;

    const COLOR string = "red";
    const COLOR string = "blue";

Instead, give each declaration a unique name:

> [!TIP]
> **Correct**

    library test.good.fi0034b;

    const COLOR string = "red";
    const OTHER_COLOR string = "blue";

Alternatively, remove one of the declarations if it was added by mistake:

> [!TIP]
> **Correct**

    library test.good.fi0034a;

    const COLOR string = "red";

For more information on choosing names, see the
[FIDL style guide](https://fuchsia.dev/docs/development/languages/fidl/guides/style#names).

## fi-0035: Canonical name collision

Two declarations cannot have the same canonical name:

> [!WARNING]
> **Incorrect**

    library test.bad.fi0035;

    const COLOR string = "red";

    protocol Color {};

Even though `COLOR` and `Color` look different, they are both represented by the
**canonical** name `color`. You get the canonical name by converting the
original name to `snake_case`.

To fix the error, give each declaration a name that is unique after
canonicalization:

> [!TIP]
> **Correct**

    library test.good.fi0035;

    const COLOR string = "red";

    protocol ColorMixer {};

Following the [FIDL style guide](https://fuchsia.dev/docs/development/languages/fidl/guides/style#names)'s naming guidelines will
minimize your chances of running into this error. Canonical name collisions will
never happen between declarations that use the same casing style, and they will
rarely happen between ones that use different styles because of other
requirements (e.g. protocol names should usually be noun phrases ending in -er).

FIDL enforces this rule because bindings generators transform names to the
idiomatic naming style for the target language. By ensuring unique canonical
names, we guarantee that bindings can do this without producing name collisions.
See [RFC-0040: Identifier uniqueness](https://fuchsia.dev/docs/contribute/governance/rfcs/0040_identifier_uniqueness) for more details.

## fi-0036: Name overlap

Declarations with the same name cannot have overlapping availabilities:

> [!WARNING]
> **Incorrect**

    @available(added=1)
    library test.bad.fi0036;

    type Color = strict enum {
        RED = 1;
    };

    @available(added=2)
    type Color = flexible enum {
        RED = 1;
    };

Instead, use the `@available` attribute to make sure only one of the
declarations is present at any given version:

> [!TIP]
> **Correct**

    @available(added=1)
    library test.good.fi0036;

    @available(replaced=2)
    type Color = strict enum {
        RED = 1;
    };

    @available(added=2)
    type Color = flexible enum {
        RED = 1;
    };

Alternatively, rename or remove one of the declarations as shown in
[fi-0034](https://fuchsia.dev/fuchsia-src/reference/fidl/language/errcat#fi-0034).

See [FIDL versioning](https://fuchsia.dev/docs/reference/fidl/language/versioning) to learn more about versioning.

## fi-0037: Canonical name overlap

Declarations with the same canonical name cannot have overlapping
availabilities:

> [!WARNING]
> **Incorrect**

    @available(added=1)
    library test.bad.fi0037;

    const COLOR string = "red";

    @available(added=2)
    protocol Color {};

Even though `COLOR` and `Color` look different, they are both represented by the
**canonical** name `color`. You get the canonical name by converting the
original name to `snake_case`.

To fix the error, give each declaration a name that is unique after
canonicalization.

> [!TIP]
> **Correct**

    @available(added=1)
    library test.good.fi0037;

    const COLOR string = "red";

    @available(added=2)
    protocol ColorMixer {};

Alternatively, change one of the declarations availabilities as shown in
[fi-0036](https://fuchsia.dev/fuchsia-src/reference/fidl/language/errcat#fi-0036), or remove the declaration.

See [fi-0035](https://fuchsia.dev/fuchsia-src/reference/fidl/language/errcat#fi-0035) for more details on why FIDL requires declarations to
have unique canonical names.

## fi-0038: Name conflicts with import

A declaration cannot have the same name as a library imported with `using`:

> [!WARNING]
> **Incorrect**

    library dependency;

    const VALUE uint32 = 1;

    library test.bad.fi0038b;

    using dependency;

    type dependency = struct {};

    // Without this, we'd get fi-0178 instead.
    const USE_VALUE uint32 = dependency.VALUE;

Instead, import the library under a different name with the `using` ... `as`
syntax:

> [!TIP]
> **Correct**

    library test.good.fi0038b;

    using dependency as dep;

    type dependency = struct {};

    const USE_VALUE uint32 = dep.VALUE;

Alternatively, rename the declaration to avoid the conflict:

> [!TIP]
> **Correct**

    library test.good.fi0038c;

    using dependency;

    type OtherName = struct {};

    const USE_VALUE uint32 = dependency.VALUE;

You can avoid this problem by using multiple components in library names. For
example, FIDL libraries in the Fuchsia SDK start with `fuchsia.`, so they have
at least two components and cannot conflict with declaration names.

This error exists to prevent ambiguities. For example, if `dependency` were an
enum with a member called `VALUE`, it would be ambiguous whether
`dependency.VALUE` referred to that enum member or to the const declared in the
imported library.

## fi-0039: Canonical name conflicts with import

A declaration cannot have the same canonical name as a library import with
`using`:

> [!WARNING]
> **Incorrect**

    library dependency;

    const VALUE uint32 = 1;

    library test.bad.fi0039b;

    using dependency;

    type Dependency = struct {};

    // Without this, we'd get fi-0178 instead.
    const USE_VALUE uint32 = dependency.VALUE;

Even though `dependency` and `Dependency` look different, they are both
represented by the **canonical** name `dependency`. You get the canonical name
by converting the original name to `snake_case`.

To fix the error, import the library under a different name with the `using` ...
`as` syntax:

> [!TIP]
> **Correct**

    library test.good.fi0039b;

    using dependency as dep;

    type Dependency = struct {};

    const USE_VALUE uint32 = dep.VALUE;

Alternatively, rename the declaration to avoid the conflict:

> [!TIP]
> **Correct**

    library test.good.fi0039c;

    using dependency;

    type OtherName = struct {};

    const USE_VALUE uint32 = dependency.VALUE;

See [fi-0038](https://fuchsia.dev/fuchsia-src/reference/fidl/language/errcat#fi-0038) to learn why this error exists and how to avoid it.

See [fi-0035](https://fuchsia.dev/fuchsia-src/reference/fidl/language/errcat#fi-0035) for more details on why FIDL requires declarations to
have unique canonical names.

## fi-0040: Files disagree on library name

Libraries can be composed of multiple files, but each file must have the same
name:

> [!WARNING]
> **Incorrect**

    library test.bad.fi0040a;

    library test.bad.fi0040b;

Ensure that all files used by a library share the same name:

> [!TIP]
> **Correct**

    library test.good.fi0040;

    library test.good.fi0040;

An encouraged convention for multi-file libraries is to create an otherwise
empty [overview.fidl](https://fuchsia.dev/docs/development/languages/fidl/guides/style#library-overview) file to serve as the main "entry
point" into the library. The `overview.fidl` file is also the appropriate place
to put library-scoped `@available` platform
[specifications](https://fuchsia.dev/docs/reference/fidl/language/versioning#syntax).

## fi-0041: Multiple libraries with same name

Each library passed to `fidlc` must have a unique name:

> [!WARNING]
> **Incorrect**

    library test.bad.fi0041;

    library test.bad.fi0041;

Ensure that all libraries have unique names:

> [!TIP]
> **Correct**

    library test.good.fi0041a;

    library test.good.fi0041b;

This error is often caused by arguments being supplied to `fidlc` in an
incorrect manner. The constituent files that make up each library necessary for
compilation (that is, the library being compiled and all of its transitive
dependencies) must be supplied as a single space-separated list of files passed
via the `--files` argument, with one such flag per library. A common mistake is
to try to pass the file for all libraries in a single `--files` list.

## fi-0042: Duplicate library import

Dependencies cannot be imported multiple times:

> [!WARNING]
> **Incorrect**

    library test.bad.fi0042a;

    type Bar = struct {};

    library test.bad.fi0042b;

    using test.bad.fi0042a;
    using test.bad.fi0042a; // duplicated
    type Foo = struct {
        bar test.bad.fi0042a.Bar;
    };

Ensure that each dependency is only imported once:

> [!TIP]
> **Correct**

    library test.good.fi0042a;

    type Bar = struct {};

    library test.good.fi0042b;

    using test.good.fi0042a;
    type Foo = struct {
        bar test.good.fi0042a.Bar;
    };

It is worth noting that FIDL does not support importing different versions of
the same library. The `@available` version is resolved for the entire `fidlc`
compilation via the `--available` flag, meaning that both the library being
compiled and all of its dependencies must share the same version for any given
compilation run.

## fi-0043: Conflicting library imports

Imported libraries are prohibited from being aliased in such a way that they
conflict with the non-aliased names of other imported libraries:

> [!WARNING]
> **Incorrect**

    library test.bad.fi0043a;

    type Bar = struct {};


    // This library has a one component name to demonstrate the error.
    library fi0043b;

    type Baz = struct {};

    library test.bad.fi0043c;

    using test.bad.fi0043a as fi0043b; // conflict
    using fi0043b;

    type Foo = struct {
        a fi0043b.Bar;
        b fi0043b.Baz;
    };

Choose a different alias to resolve the name conflict:

> [!TIP]
> **Correct**

    library test.good.fi0043a;

    type Bar = struct {};

    library fi0043b;

    type Baz = struct {};

    library test.good.fi0043c;

    using test.good.fi0043a as dep;
    using fi0043b;

    type Foo = struct {
        a dep.Bar;
        b fi0043b.Baz;
    };

## fi-0044: Conflicting library import aliases

Imported libraries are prohibited from being aliased in such a way that they
conflict with the aliases assigned to other imported libraries:

> [!WARNING]
> **Incorrect**

    library test.bad.fi0044a;

    type Bar = struct {};

    library test.bad.fi0044b;

    type Baz = struct {};

    library test.bad.fi0044c;

    using test.bad.fi0044a as dep;
    using test.bad.fi0044b as dep; // conflict
    type Foo = struct {
        a dep.Bar;
        b dep.Baz;
    };

Choose non-conflicting aliases to resolve the name conflict:

> [!TIP]
> **Correct**

    library test.good.fi0044a;

    type Bar = struct {};

    library test.good.fi0044b;

    type Baz = struct {};

    library test.good.fi0044c;

    using test.good.fi0044a as dep1;
    using test.good.fi0044b as dep2;
    type Foo = struct {
        a dep1.Bar;
        b dep2.Baz;
    };

## fi-0045: Attributes disallowed on using declarations

Attributes cannot be attached to `using` declarations:

> [!WARNING]
> **Incorrect**

    library test.bad.fi0045a;

    type Bar = struct {};

    library test.bad.fi0045b;

    /// not allowed
    @also_not_allowed
    using test.bad.fi0045a;

    type Foo = struct {
        bar test.bad.fi0045a.Bar;
    };

Remove the attribute to resolve the error:

> [!TIP]
> **Correct**

    library test.good.fi0045a;

    type Bar = struct {};

    library test.good.fi0045b;

    using test.good.fi0045a;

    type Foo = struct {
        bar test.good.fi0045a.Bar;
    };

This restriction applies to `/// ...` doc comments as well, as those are merely
syntactic sugar for the `@doc("...")` attribute.

## fi-0046: Unknown library

In most cases, this problem is due to the dependency being misspelled or not provided by the build system.
If the dependency in question is intentionally unused, the relevant using line must be removed:

> [!WARNING]
> **Incorrect**

    library test.bad.fi0046;

    using dependent; // unknown using.

    type Foo = struct {
        dep dependent.Bar;
    };

Make sure all imports are added as dependencies to the library using the build system.

> [!TIP]
> **Correct**

    library test.good.fi0046;

    type Foo = struct {
        dep int64;
    };

## fi-0047

> [!WARNING]
> **Deprecated:** This error code has been retired.

## fi-0048: Optional table member

Table members types cannot be `optional`:

> [!WARNING]
> **Incorrect**

    library test.bad.fi0048;

    type Foo = table {
        // Strings can be optional in general, but not in table member position.
        1: t string:optional;
    };

Remove the `optional` constraint from all members:

> [!TIP]
> **Correct**

    library test.good.fi0048;

    type Foo = table {
        1: t string;
    };

Table members are always optional, so specifying this fact on the member's underlying type is redundant.

Table members are always optional because, on the wire, each table member is represented as an entry in a vector.
This vector is always represents all known fields on the table, so every omitted table member is represented
as a null envelope - exactly equivalent to the representation of an omitted optional type.

## fi-0049: Optional union member

Union members cannot be optional:

> [!WARNING]
> **Incorrect**

    library test.bad.fi0049;

    type Foo = strict union {
        // Strings can be optional in general, but not in unions.
        1: bar string:optional;
    };

Remove the `optional` constraint:

> [!TIP]
> **Correct**

    library test.good.fi0049;

    type Foo = strict union {
        1: bar string;
    };

FIDL does not allow union members to be optional because this can result in many ways of expressing the same value.
For example, a union with three optional members would have 6 states (2 per member). Instead, this should be modeled with a
fourth member whose type is `struct {}`, or by making the overall union optional with `Foo:optional`.

## fi-0050: Deprecated struct default syntax prohibited

Previously, FIDL allowed for default values to be set on `struct` members:

> [!WARNING]
> **Incorrect**

    library test.bad.fi0050;

    type MyStruct = struct {
        field int64 = 20;
    };

As of [RFC-0160: Remove support for FIDL struct defaults](https://fuchsia.dev/docs/contribute/governance/rfcs/0160_fidl_remove_struct_defaults), this behavior is
disallowed:

> [!TIP]
> **Correct**

    library test.good.fi0050;

    type MyStruct = struct {
        field int64;
    };

Default values for `struct` members are no longer allowed. Users should set such
defaults in application logic instead.

A small number of legacy users of this syntax are allowed to continue using it
behind an allowlist built into the compiler, but no new exceptions are being
made to add to this list. As soon as these users are migrated off, this feature
will be permanently removed from FIDL.

## fi-0051: Unknown dependent library

This error occurs when you use a symbol that's from an unknown library.

> [!WARNING]
> **Incorrect**

    library test.bad.fi0051;

    type Company = table {
        1: employees vector<unknown.dependent.library.Person>;
        2: name string;
    };

To fix this, import the missing dependent library with a using declaration.

> [!TIP]
> **Correct**

    library known.dependent.library;

    type Person = table {
        1: age uint8;
        2: name string;
    };

    library test.good.fi0051;
    using known.dependent.library;

    type Company = table {
        1: employees vector<known.dependent.library.Person>;
        2: name string;
    };

This error commonly occurs when the `fidlc` command line invocation is
improperly formed. If you are confident that the unknown library exists and
should be resolvable, make sure you are passing the dependent library's files
correctly via a space-separated list passed to the `--files` flag.

## fi-0052: Name not found

This error occurs when you use a name that the FIDL compiler cannot find.

> [!WARNING]
> **Incorrect**

    library test.bad.fi0052;

    protocol Parser {
        Tokenize() -> (struct {
            tokens vector<string>;
        }) error ParsingError; // ParsingError doesn't exist.
    };

To fix this, either remove the name that's not found:

> [!TIP]
> **Correct**

    library test.good.fi0052a;

    protocol Parser {
        Tokenize() -> (struct {
            tokens vector<string>;
        });
    };

or define the name that's not found:

    library test.good.fi0052b;

    type ParsingError = flexible enum {
        UNEXPECTED_EOF = 0;
    };

    protocol Parser {
        Tokenize() -> (struct {
            tokens vector<string>;
        }) error ParsingError;
    };

## fi-0053: Cannot refer to member

This error occurs when you refer to a member that's not a `bits` or `enum` entry.

> [!WARNING]
> **Incorrect**

    library test.bad.fi0053a;

    type Person = struct {
        name string;
        birthday struct {
            year uint16;
            month uint8;
            day uint8;
        };
    };

    const JOHNS_NAME Person.name = "John Johnson"; // Cannot refer to member of struct 'Person'.

    library test.bad.fi0053b;

    type Person = struct {
        name string;
        birthday struct {
            year uint16;
            month uint8;
            day uint8;
        };
    };

    type Cat = struct {
        name string;
        age Person.birthday; // Cannot refer to member of struct 'Person'.
    };

To fix this error, either change to a named type:

> [!TIP]
> **Correct**

    library test.good.fi0053a;

    type Person = struct {
        name string;
        birthday struct {
            year uint16;
            month uint8;
            day uint8;
        };
    };

    const JOHNS_NAME string = "John Johnson";

or extract the member's type:

    library test.good.fi0053b;

    type Date = struct {
        year uint16;
        month uint8;
        day uint8;
    };

    type Person = struct {
        name string;
        birthday Date;
    };

    type Cat = struct {
        name string;
        age Date;
    };

## fi-0054: Invalid bits/enum member

This error occurs when an `enum` or `bits` member is referenced without being previously defined.

> [!WARNING]
> **Incorrect**

    library test.bad.fi0054;

    type Enum = enum {
        foo_bar = 1;
    };

    const EXAMPLE Enum = Enum.FOO_BAR;

To avoid this error, confirm that you have previously declared a value for the referenced
member value. These values are case sensitive.

> [!TIP]
> **Correct**

    library test.good.fi0054;

    type Enum = enum {
        foo_bar = 1;
    };

    const EXAMPLE Enum = Enum.foo_bar;

## fi-0055: Invalid reference to deprecated

This error occurs when you use a reference to a `type` or `const` a with an
incompatible `@available` attribute. This typically happens when using
deprecated `types` or `consts` from later versions.

> [!WARNING]
> **Incorrect**

    @available(added=1)
    library test.bad.fi0055;

    @available(added=1, deprecated=2, note="use Color instead")
    alias RGB = array<uint8, 3>;

    @available(added=2)
    type Color = struct {
        r uint8;
        g uint8;
        b uint8;
        a uint8;
    };

    @available(added=3)
    type Config = table {
        // RGB is deprecated in version 2.
        1: color RGB;
    };

To fix this error, use a non-deprecated `type` or `const`:

> [!TIP]
> **Correct**

    @available(added=1)
    library test.good.fi0055;

    @available(added=1, deprecated=2, note="use Color instead")
    alias RGB = array<uint8, 3>;

    @available(added=2)
    type Color = struct {
        r uint8;
        g uint8;
        b uint8;
        a uint8;
    };

    @available(added=3)
    type Config = table {
        // Using a non-deprecated type.
        1: color Color;
    };

## fi-0056: Invalid reference to deprecated other platform

This error occurs when you use a reference to a `type` or `const` from another
platform with an incompatible `@available` attribute. This typically happens
when using deprecated `types` or `consts` from later versions.

> [!WARNING]
> **Incorrect**

    @available(platform="foo", added=1)
    library test.bad.fi0056a;

    @available(added=1, deprecated=2, note="use Color instead")
    alias RGB = array<uint8, 3>;

    @available(added=2)
    type Color = struct {
        r uint8;
        g uint8;
        b uint8;
        a uint8;
    };

    @available(platform="bar", added=2)
    library test.bad.fi0056b;

    using test.bad.fi0056a;

    @available(added=3)
    type Config = table {
        // RGB is deprecated in version 2.
        1: color test.bad.fi0056a.RGB;
    };

To fix this error, use a non-deprecated `type` or `const`:

> [!TIP]
> **Correct**

    @available(platform="foo", added=1)
    library test.good.fi0056a;

    @available(added=1, deprecated=2, note="use Color instead")
    alias RGB = array<uint8, 3>;

    @available(added=2)
    type Color = struct {
        r uint8;
        g uint8;
        b uint8;
        a uint8;
    };

    @available(platform="bar", added=2)
    library test.good.fi0056b;

    using test.good.fi0056a;

    @available(added=2)
    type Config = table {
        // Change to use a non-deprecated type.
        1: color test.good.fi0056a.Color;
    };

## fi-0057: Includes cycle

There are a number of situations that could cause this problem to occur, but all
of them basically boil down to a FIDL declaration referring to itself in an
unresolvable way. The simplest form of this error is when a type or protocol
refers directly to itself in its own definition:

> [!WARNING]
> **Incorrect**

    library test.bad.fi0057c;

    type MySelf = struct {
        me MySelf;
    };

More complex failure cases are possible when a type or protocol *transitively*
refers to itself via at least one level of indirection:

> [!WARNING]
> **Incorrect**

    library test.bad.fi0057a;

    type Yin = struct {
        yang Yang;
    };

    type Yang = struct {
        yin Yin;
    };

    library test.bad.fi0057b;

    protocol Yin {
        compose Yang;
    };

    protocol Yang {
        compose Yin;
    };

This error can be resolved by adding an envelope (aka, optionality) somewhere in
the inclusion cycle, as this allows the cycle to be "broken" at encode/decode
time:

> [!TIP]
> **Correct**

    library test.good.fi0057;

    type MySelf = struct {
        me box<MySelf>;
    };

> [!CAUTION]
> **Caution:** This feature is not yet implemented for all viable cases; for instance, the following code will currently fail, despite including the requisite envelope between the recursive reference and its definition. This is because recursive types have not yet fully implemented: <https://fxbug.dev/42110612>.

    library test.bad.fi0057d;

    type MySelf = table {
        1: me MySelf;
    };

Recursive types that are unbroken by envelopes are disallowed because they would
be impossible to encode. In the first example above, encoding `MySelf` would
require first encoding an instance of `MySelf`, which would in turn require
encoding an instance of `MySelf`, ad inifitum. A solution to this problem is to
add a "break" in this chain via optionality, where one may choose to either
encode another nested instance of `MySelf`, or otherwise encode a null envelope
with no further data.

## fi-0058: Reference to compiler generated payload name

Anonymous method payloads have their names automatically generated by the FIDL
compiler, so that users of generated backend code may refer to the types they
represent as necessary. Referring to these types in \*.fidl files themselves,
however, is forbidden:

> [!WARNING]
> **Incorrect**

    library test.bad.fi0058;

    protocol MyProtocol {
        strict MyInfallible(struct {
            in uint8;
        }) -> (struct {
            out int8;
        });
        strict MyFallible(struct {
            in uint8;
        }) -> (struct {
            out int8;
        }) error flexible enum {};
        strict -> MyEvent(struct {
            out int8;
        });
    };

    type MyAnonymousReferences = struct {
        a MyProtocolMyInfallibleRequest;
        b MyProtocolMyInfallibleResponse;
        c MyProtocolMyFallibleRequest;
        d MyProtocol_MyFallible_Result;
        e MyProtocol_MyFallible_Response;
        f MyProtocol_MyFallible_Error;
        g MyProtocolMyEventRequest;
    };

If you wish to refer to the payload type directly, you should extract the
payload type into its own named type declaration instead:

> [!TIP]
> **Correct**

    library test.good.fi0058;

    type MyRequest = struct {
        in uint8;
    };
    type MyResponse = struct {
        out int8;
    };
    type MyError = flexible enum {};

    protocol MyProtocol {
        strict MyInfallible(MyRequest) -> (MyResponse);
        strict MyFallible(MyRequest) -> (MyResponse) error MyError;
        strict -> MyEvent(MyResponse);
    };

    type MyAnonymousReferences = struct {
        a MyRequest;
        b MyResponse;
        c MyRequest;
        // There is no way to explicitly name the error result union.
        // d MyProtocol_MyFallible_Result;
        e MyResponse;
        f MyError;
        g MyResponse;
    };

All FIDL methods and events reserve the `[PROTOCOL_NAME][METHOD_NAME]Request`
name for their anonymous request payloads. Strict, infallible two-way methods
additionally reserve `[PROTOCOL_NAME][METHOD_NAME]Response`. Two-way methods
that are flexible or fallible instead reserve:

- `[PROTOCOL_NAME]_[METHOD_NAME]_Result`
- `[PROTOCOL_NAME]_[METHOD_NAME]_Response`
- `[PROTOCOL_NAME]_[METHOD_NAME]_Error`

These names use underscores unlike the others for historical reasons.

## fi-0059: Invalid constant type

Not all types can used in `const` declarations:

> [!WARNING]
> **Incorrect**

    library test.bad.fi0059;

    const MY_CONST string:optional = "foo";

Convert to an allowed type, if possible:

> [!TIP]
> **Correct**

    library test.good.fi0059;

    const MY_CONST string = "foo";

Only FIDL primitives (`bool`, `int8`, `int16`, `int32`, `int64`, `uint8`,
`uint16`, `uint32`, `uint64`, `float32`, `float64`) and non-optional `string`
types may be used in the left-hand side of a `const` declaration.

## fi-0060: Cannot resolve constant value

Constant values must be resolvable to known values:

> [!WARNING]
> **Incorrect**

    library test.bad.fi0060;

    const MY_CONST bool = optional;

Make sure that the constant being used is a valid value:

> [!TIP]
> **Correct**

    library test.good.fi0060;

    const MY_CONST bool = true;

This error often accompanies other errors, which provide more information on the
nature of the non-resolvable expected constant.

## fi-0061: Or operator on non-primitive values

The binary-or operator can only be used on primitives:

> [!WARNING]
> **Incorrect**

    library test.bad.fi0061;

    const HI string = "hi";
    const THERE string = "there";
    const OR_OP string = HI | THERE;

Try representing the data being operated on as a `bits` enumeration instead:

> [!TIP]
> **Correct**

    library test.good.fi0061;

    type MyBits = flexible bits {
        HI = 0x1;
        THERE = 0x10;
    };
    const OR_OP MyBits = MyBits.HI | MyBits.THERE;

## fi-0062: Newtypes are not allowed

Newtypes from [RFC-0052: Type aliasing and new types](https://fuchsia.dev/docs/contribute/governance/rfcs/0052_type_aliasing_named_types) are not
fully implementented and cannot be used yet:

> [!WARNING]
> **Incorrect**

    library test.bad.fi0062;

    type Matrix = array<float64, 9>;

In the meantime, you can achieve something similar by defining a struct with a
single element:

> [!TIP]
> **Correct**

    library test.good.fi0062a;

    type Matrix = struct {
        elements array<float64, 9>;
    };

Alternatively, you can define an alias, but note that unlike a newtype this
provides no type safety (that is, it can be used interchangeably with its
underlying type):

> [!TIP]
> **Correct**

    library test.good.fi0062b;

    alias Matrix = array<float64, 9>;

## fi-0063: Expected value but got type

The right-hand side of a `const` declaration must resolve to a constant value,
not a type:

> [!WARNING]
> **Incorrect**

    library test.bad.fi0063;

    type MyType = struct {};
    const MY_CONST uint32 = MyType;

Ensure that the right-hand side is a value:

> [!TIP]
> **Correct**

    library test.good.fi0063;

    const MY_VALUE uint32 = 8;
    const MY_CONST uint32 = MY_VALUE;

## fi-0064: Incorrect bits or enum value type

When using a `bits` or `enum` variant as the value in a `const` declaration, the
type of the `bits`/`enum` value must be the same as the left-hand side of the
const declaration:

> [!WARNING]
> **Incorrect**

    library test.bad.fi0064;

    type MyEnum = enum : int32 {
        VALUE = 1;
    };
    type OtherEnum = enum : int32 {
        VALUE = 5;
    };
    const MY_CONST MyEnum = OtherEnum.VALUE;

One solution is to change the `const` declaration's type to match that of the
value being stored:

> [!TIP]
> **Correct**

    library test.good.fi0064;

    type MyEnum = enum : int32 {
        VALUE = 1;
    };
    type OtherEnum = enum : int32 {
        VALUE = 5;
    };
    const MY_CONST OtherEnum = OtherEnum.VALUE;

Alternatively, a different value can be selected to match the `const`
declaration's type:

> [!TIP]
> **Correct**

    library test.good.fi0064;

    type MyEnum = enum : int32 {
        VALUE = 1;
    };
    type OtherEnum = enum : int32 {
        VALUE = 5;
    };
    const MY_CONST MyEnum = MyEnum.VALUE;

## fi-0065: Cannot convert value to expected type

A constant value must be of a type appropriate for the location it is being
used.

The most common cause for this error is when a `const` declaration's value does
not match its stated type:

> [!WARNING]
> **Incorrect**

    library test.bad.fi0065a;

    const MY_CONST bool = "foo";

This can still be problematic when a correctly defined `const` value is used in
a location where its underlying type is invalid:

> [!WARNING]
> **Incorrect**

    library test.bad.fi0065b;

    const ONE uint8 = 0x0001;
    const TWO_FIFTY_SIX uint16 = 0x0100;
    const TWO_FIFTY_SEVEN uint8 = ONE | TWO_FIFTY_SIX;

Additionally, FIDL's [official](https://fuchsia.dev/docs/reference/fidl/language/attributes) check their arguments
against a schema. Because these arguments are themselves constant values, the
same kind of type mismatch can occur:

> [!WARNING]
> **Incorrect**

    library test.bad.fi0065c;

    protocol MyProtocol {
        @selector(3840912312901827381273)
        MyMethod();
    };

In all of these cases, the solution is to use only use values of the expected
type in locations where `const` values are accepted. The above cases become,
respectively:

> [!TIP]
> **Correct**

    library test.good.fi0065a;

    const MY_CONST string = "foo";

> [!TIP]
> **Correct**

    library test.good.fi0065b;

    const ONE uint8 = 0x0001;
    const TWO_FIFTY_SIX uint16 = 0x0100;
    const TWO_FIFTY_SEVEN uint16 = ONE | TWO_FIFTY_SIX;

> [!TIP]
> **Correct**

    library test.good.fi0065c;

    protocol MyProtocol {
        @selector("MyOldMethod")
        MyMethod();
    };

## fi-0066: Constant overflows type

A constant value cannot fall outside of the range inherent to its underlying
type:

> [!WARNING]
> **Incorrect**

    library test.bad.fi0066;

    const NUM uint64 = -42;

The problem may be fixed either by changing the value to fit within the type's
range:

> [!TIP]
> **Correct**

    library test.good.fi0066a;

    const NUM uint64 = 42;

Or otherwise by changing to the type to accommodate the currently overflowing
value:

> [!TIP]
> **Correct**

    library test.good.fi0066b;

    const NUM int64 = -42;

This error exclusively concerns FIDL's numeric types, all of which have the
capacity to overflow. The ranges are sourced from the C++ `std::numeric_limits`
[interface](https://en.cppreference.com/w/cpp/types/climits) and are as follows:

| Type | Minimum | Maximum |
|---|---|---|
| `int8` | -128 | 127 |
| `int16` | 32768 | 32767 |
| `int32` | 2147483648 | 2147483647 |
| `int64` | 9223372036854775808 | 9223372036854775807 |
| `uint8` | 0 | 255 |
| `uint16` | 0 | 65536 |
| `uint32` | 0 | 4294967295 |
| `uint64` | 0 | 18446744073709551615 |
| `float32` | -3.40282e+38 | 3.40282e+38 |
| `float64` | -1.79769e+308 | 1.79769e+308 |

## fi-0067: Bits member must be power of two

The values of all members in a `bits` declaration must not be any number that is
not a power of two:

> [!WARNING]
> **Incorrect**

    library test.bad.fi0067;

    type NonPowerOfTwo = bits : uint64 {
        THREE = 3;
    };

Instead, member values should always be powers of two:

> [!TIP]
> **Correct**

    library test.good.fi0067a;

    type Fruit = bits : uint64 {
        ORANGE = 1;
        APPLE = 2;
        BANANA = 4;
    };

An easy way to avoid getting tripped up by this restriction is to just use bit
masks, rather than decimal numbers, for bit member values:

> [!TIP]
> **Correct**

    library test.good.fi0067b;

    type Life = bits {
        A = 0b000010;
        B = 0b001000;
        C = 0b100000;
    };

The `bits` construct represents a [bit array](https://en.wikipedia.org/wiki/Bit_array). This is the most
memory-efficient way to represent a sequence of boolean flags. Because each
member of the `bits` declaration is mapped to a specific bit of its underlying
memory, the values used for that mapping must clearly identify a specific bit in
an unsigned integer to assign to.

## fi-0068: Flexible enums have a reserved unknown value

This error happens when you define an enum member whose value clashes with the
reserved unknown value.

Flexible enums may hold values not known by the FIDL schema. In addition,
flexible enums always reserve some value which will be treated as unknown.
By default, that value is the maximum numerical value representable by the
underlying integer type of that enum (e.g. `255` in case of `uint8`).

> [!WARNING]
> **Incorrect**

    library test.bad.fi0068;

    type Foo = flexible enum : uint8 {
        ZERO = 0;
        ONE = 1;
        MAX = 255;
    };

To fix the error, you may remove the member or change its value:

> [!TIP]
> **Correct**

    library test.good.fi0068a;

    type Foo = flexible enum : uint8 {
        ZERO = 0;
        ONE = 1;
    };

    library test.good.fi0068b;

    type Foo = flexible enum : uint8 {
        ZERO = 0;
        ONE = 1;
        MAX = 254;
    };

Finally, if you come across this error when transitioning a `strict` enum to a
`flexible` enum, you may use the `@unknown` attribute to designate the numerical
value of a particular member as the unknown value. See [`@unknown`](https://fuchsia.dev/docs/reference/fidl/language/attributes#unknown).

## fi-0069: Bits must use unsigned integral subtype

Using signed numerics as the underlying type for a `bits` declaration is
prohibited:

> [!WARNING]
> **Incorrect**

    library test.bad.fi0069;

    type Fruit = bits : int64 {
        ORANGE = 1;
        APPLE = 2;
        BANANA = 4;
    };

Instead, use any one of the following: `uint8`, `uint16`, `uint32`, or `uint64`:

> [!TIP]
> **Correct**

    library test.good.fi0069;

    type Fruit = bits : uint64 {
        ORANGE = 1;
        APPLE = 2;
        BANANA = 4;
    };

Unlike `enum` declarations, which allow both signed and unsigned integers (see:
[fi-0070](https://fuchsia.dev/fuchsia-src/reference/fidl/language/errcat#fi-0070)), `bits` declarations only permit the latter. This is
because each `bits` member necessarily represents a specific underlying bit in a
[bit array](https://en.wikipedia.org/wiki/Bit_array) (this is the reason that [fi-0067](https://fuchsia.dev/fuchsia-src/reference/fidl/language/errcat#fi-0067)
exists). This is most cleanly represented as a single unsigned integer. The
binary representation of unsigned integer maps directly to a single bit (2 to
the power of its index), whereas the negative numbers in signed integers almost
always select multiple bits due to the mechanics of the [two's complement
representation](https://en.wikipedia.org/wiki/Two%27s_complement).

> [!NOTE]
> **Note:** if the value given for the underlying type of a `bits` is not an identifier for a type, it will result in [fi-0013: Invalid wrapped
> type](https://fuchsia.dev/fuchsia-src/reference/fidl/language/errcat#fi-0013) instead.

## fi-0070: Enum must use integral subtype

Using the non-integral numerics `float32` or `float64` as the underlying type
for an `enum` declaration is prohibited:

> [!WARNING]
> **Incorrect**

    library test.bad.fi0070;

    type MyEnum = enum : float64 {
        ONE_POINT_FIVE = 1.5;
    };

Instead, use any one of the following: `int8`, `int16`,`int32`,`int64`, `uint8`,
`uint16`, `uint32`, or `uint64`:

> [!TIP]
> **Correct**

    library test.good.fi0070;

    type MyEnum = enum : uint64 {
        ONE = 1;
    };

> [!NOTE]
> **Note:** if the value given for the underlying type of an `enum` is not an identifier for a type, it will result in [fi-0013: Invalid wrapped
> type](https://fuchsia.dev/fuchsia-src/reference/fidl/language/errcat#fi-0013) instead.

## fi-0071: Unknown attribute disallowed on strict enum members

A `strict enum` must not have any members annotated with the `@unknown`
attribute:

> [!WARNING]
> **Incorrect**

    library test.bad.fi0071;

    type MyEnum = strict enum : int8 {
        @unknown
        UNKNOWN = 0;
        FOO = 1;
        MAX = 127;
    };

To continue using the `@unknown` attribute, change to a `flexible enum`:

> [!TIP]
> **Correct**

    library test.good.fi0071a;

    type MyEnum = flexible enum : int8 {
        @unknown
        UNKNOWN = 0;
        FOO = 1;
        MAX = 127;
    };

Otherwise, just remove the attribute altogether to remain a `strict enum`:

> [!TIP]
> **Correct**

    library test.good.fi0071;

    type MyEnum = strict enum : int8 {
        UNKNOWN = 0;
        FOO = 1;
        MAX = 127;
    };

The purpose of the `@unknown` [attribute](https://fuchsia.dev/docs/reference/fidl/language/attributes#unknown) is to
smooth over a transition from a `strict enum` with a user-defined unknown value,
like this into a `flexible enum` with unknown values known to and handled by
FIDL. In the above example, it would be used to transition from the second
correct usage to the first one.

## fi-0072: Only enum member can carry the unknown attribute

Adorning multiple `enum` members with the `@unknown` attribute is prohibited:

> [!WARNING]
> **Incorrect**

    library test.bad.fi0072;

    type MyEnum = flexible enum : uint8 {
        @unknown
        UNKNOWN = 0;
        @unknown
        OTHER = 1;
    };

Choose and annotate only the member that is used as a domain specific "unknown"
value:

> [!TIP]
> **Correct**

    library test.good.fi0071a;

    type MyEnum = flexible enum : int8 {
        @unknown
        UNKNOWN = 0;
        OTHER = 1;
    };

The purpose of the `@unknown` [attribute](https://fuchsia.dev/docs/reference/fidl/language/attributes#unknown) is to
smooth over a transition from a `strict enum` with a user-defined unknown value,
like this into a `flexible enum` with unknown values known to and handled by
FIDL:

> [!TIP]
> **Correct**

    library test.good.fi0072;

    type MyEnum = strict enum : int8 {
        UNKNOWN = 0;
        OTHER = 1;
    };

> [!TIP]
> **Correct**

    library test.good.fi0071a;

    type MyEnum = flexible enum : int8 {
        @unknown
        UNKNOWN = 0;
        OTHER = 1;
    };

## fi-0073: Composing non-protocol

Only protocols can be used in `compose` statements:

> [!WARNING]
> **Incorrect**

    library test.bad.fi0073;

    type MyStruct = struct {};

    protocol MyProtocol {
        compose MyStruct;
    };

Make sure the name you are referring to points to a protocol:

> [!TIP]
> **Correct**

    library test.good.fi0073;

    protocol MyOtherProtocol {};

    protocol MyProtocol {
        compose MyOtherProtocol;
    };

## fi-0074: Invalid layout used for method payload

Only `struct`, `table`, or `union` layouts may be used to describe method
payloads:

> [!WARNING]
> **Incorrect**

    library test.bad.fi0074;

    protocol MyProtocol {
        MyMethod(enum {
            FOO = 1;
        });
    };

Use one of those layouts instead:

> [!TIP]
> **Correct**

    library test.good.fi0074;

    protocol MyProtocol {
        MyMethod(struct {
            foo bool;
        });
    };

## fi-0075: Invalid primitive used for method payload

Primitives cannot be used as method method payload:

> [!WARNING]
> **Incorrect**

    library test.bad.fi0075;

    protocol MyProtocol {
        MyMethod(uint32);
    };

Use a type of the `struct`, `table`, or `union` layout instead:

> [!TIP]
> **Correct**

    library test.good.fi0075;

    protocol MyProtocol {
        MyMethod(struct {
            wrapped_in_struct uint32;
        });
    };

For cases where the desirable payload really is just a primitive value, and
future evolution is not a concern, wrapping the value in a `struct` layout will
result in a payload that is the same size as desired value is by itself.

## fi-0076

> [!WARNING]
> **Deprecated:** This error code has been retired.

## fi-0077: Interaction payload cannot be empty struct

The payloads in a method or event cannot be empty structs:

> [!WARNING]
> **Incorrect**

    library test.bad.fi0077a;

    protocol Test {
        MyMethod(struct {}) -> (struct {});
    };

    library test.bad.fi0077b;

    protocol Test {
        -> MyEvent(struct {});
    };

If you would like to express that a particular request/response does not hold
any information, delete the empty struct, leaving `()` in that location:

> [!TIP]
> **Correct**

    library test.good.fi0077a;

    protocol Test {
        MyMethod() -> ();
    };

    library test.good.fi0077b;

    protocol Test {
        -> MyEvent();
    };

Empty structs cannot be extended, and take 1 byte on the wire. Since FIDL
supports interactions without payloads, using empty structs this way is
superfluous and less efficient. Therefore they are not allowed.

## fi-0078

> [!WARNING]
> **Deprecated:** This error code has been retired.

## fi-0079

> [!WARNING]
> **Deprecated:** This error code has been retired.

## fi-0080: Generated zero value ordinal

This error should never occur. If you managed to make it happen,
congratulations, you've probably broken SHA-256!

Joking aside, this error occurs if the fidlc compiler generates an ordinal value
of 0. It should never happen, so if it does, you've probably found a bug in the
FIDL compiler. Please report the issue to [our issue tracker](https://bugs.fuchsia.dev/p/fuchsia/issues/entry?components=FIDL) if this happens.

## fi-0081: Duplicate method ordinal

This error usually occurs when you use an [`@selector` attribute](https://fuchsia.dev/docs/reference/fidl/language/attributes#selector)
to make two method names produce the same ordinal.

> [!WARNING]
> **Incorrect**

    library test.bad.fi0081;

    protocol Parser {
        ParseLine();

        // Multiple methods with the same ordinal...
        @selector("ParseLine")
        ParseOneLine();
    };

To fix this issue, update either the method names, or selectors to not collide.

> [!TIP]
> **Correct**

    library test.good.fi0081;

    protocol Parser {
        ParseLine();

        @selector("Parse1Line")
        ParseOneLine();
    };

This error can also happen if there is a SHA-256 collision, but the chances of
this are basically zero. If you are positive your selectors aren't at fault and
you still run into this error, you've probably found a bug in the FIDL compiler.
Please report the issue to [our issue tracker](https://bugs.fuchsia.dev/p/fuchsia/issues/entry?components=FIDL) if this happens.

## fi-0082: Invalid selector value

This error occurs when you use an invalid value for an [@selector](https://fuchsia.dev/docs/reference/fidl/language/attributes#selector).
Most commonly, this is due to a typo. A selector must either be a standalone
method name, or a fully qualified method name.

> [!WARNING]
> **Incorrect**

    library test.bad.fi0082;

    protocol Parser {
        @selector("test.old.fi0082.Parser.Parse")
        Parse();
    };

To fix this, update the selector to either be a valid standalone, or fully
qualified method name:

> [!TIP]
> **Correct**

    library test.good.fi0082;

    protocol Parser {
        @selector("test.old.fi0082/Parser.Parse")
        Parse();
    };

## fi-0083: `fuchsia.io` must use explicit ordinals

The FIDL compiler used to automatically rename `fuchsia.io` ordinals to
`fuchsia.io1`. This magic was intended to make it easier to migrate to
`fuchsia.io2` by letting the `io2` versions of the methods have the "normal"
ordinal. However, this system ended up being a bit too magical so it is now
required to manually provide the ordinal for `fuchsia.io`.

> [!WARNING]
> **Incorrect**

    library fuchsia.io;

    protocol SomeProtocol {
        SomeMethod();
    };

To fix this issue, manually provide a selector using `fuchsia.io1` as the
library name to allow the `fuchsia.io` names to be used for io2.

> [!TIP]
> **Correct**

    library fuchsia.io;

    protocol SomeProtocol {
        @selector("fuchsia.io1/SomeProtocol.SomeMethod")
        SomeMethod();
    };

## fi-0084: Default members disallowed on method payload structs

> [!WARNING]
> **Warning:** Default members are no longer allowed on any new FIDL `struct` layouts.

Structs used as method paylods may not specify default members:

> [!WARNING]
> **Incorrect**

    library test.bad.fi0084;

    type MyStruct = struct {
        @allow_deprecated_struct_defaults
        a bool = false;
    };

    protocol MyProtocol {
        MyMethod(MyStruct) -> (MyStruct);
    };

Remove the default members from the relevant `struct` declaration:

> [!TIP]
> **Correct**

    library test.good.fi0084;

    type MyStruct = struct {
        a bool;
    };

    protocol MyProtocol {
        MyMethod(MyStruct) -> (MyStruct);
    };

> [!NOTE]
> **Note:** Default `struct` members have been removed by [RFC-0160: Remove support
> for FIDL struct
> defaults](https://fuchsia.dev/docs/contribute/governance/rfcs/0160_fidl_remove_struct_defaults), and are currently deprecated, with no new uses cases being supported. See [fi-0050](https://fuchsia.dev/fuchsia-src/reference/fidl/language/errcat#fi-0050) for more information.

## fi-0085

> [!WARNING]
> **Deprecated:** This error code has been retired.

## fi-0086

> [!WARNING]
> **Deprecated:** This error code has been retired.

## fi-0087

> [!WARNING]
> **Deprecated:** This error code has been retired.

## fi-0088: Service members cannot be optional

This error occurs when you mark a service member as `optional`. Marking a
service member as `optional` isn't allowed because service members are always
optional.

> [!WARNING]
> **Incorrect**

    library test.bad.fi0088;

    protocol Sorter {
        Sort(struct {
            input vector<int32>;
        }) -> (struct {
            output vector<int32>;
        });
    };

    service SortService {
        quicksort client_end:<Sorter, optional>;
        mergesort client_end:<Sorter, optional>;
    };

To fix this, remove the optional clause:

> [!TIP]
> **Correct**

    library test.good.fi0088;

    protocol Sorter {
        Sort(struct {
            input vector<int32>;
        }) -> (struct {
            output vector<int32>;
        });
    };

    service SortService {
        quicksort client_end:Sorter;
        mergesort client_end:Sorter;
    };

## fi-0089

> [!WARNING]
> **Deprecated:** This error code has been retired.

## fi-0090

> [!WARNING]
> **Deprecated:** This error code has been retired.

## fi-0091: Invalid struct member type

> [!WARNING]
> **Warning:** Default members are no longer allowed on any new FIDL `struct` layouts.

This error occurs when you try to set a default struct value for a non-supported
type. Only numeric and boolean types are allowed to set a default struct value.

> [!WARNING]
> **Incorrect**

    library test.bad.fi0091;

    type Person = struct {
        @allow_deprecated_struct_defaults
        name string:optional = "";
    };

To fix this, remove the default value:

> [!TIP]
> **Correct**

    library test.good.fi0091;

    type Person = struct {
        @allow_deprecated_struct_defaults
        name string:optional;
    };

> [!NOTE]
> **Note:** Default `struct` members have been removed by [RFC-0160: Remove support
> for FIDL struct defaults](https://fuchsia.dev/docs/contribute/governance/rfcs/0160_fidl_remove_struct_defaults), and are currently deprecated, with no new uses cases being supported. See [fi-0050](https://fuchsia.dev/fuchsia-src/reference/fidl/language/errcat#fi-0050) for more information.

## fi-0092: Table ordinal too large

FIDL table ordinals cannot be greater than 64:

> [!WARNING]
> **Incorrect**

    library test.bad.fi0092;

    type Table64thField = table {
        1: x int64;
    };

    type Example = table {
        1: v1 int64;
        2: v2 int64;
        3: v3 int64;
        4: v4 int64;
        5: v5 int64;
        6: v6 int64;
        7: v7 int64;
        8: v8 int64;
        9: v9 int64;
        10: v10 int64;
        11: v11 int64;
        12: v12 int64;
        13: v13 int64;
        14: v14 int64;
        15: v15 int64;
        16: v16 int64;
        17: v17 int64;
        18: v18 int64;
        19: v19 int64;
        20: v20 int64;
        21: v21 int64;
        22: v22 int64;
        23: v23 int64;
        24: v24 int64;
        25: v25 int64;
        26: v26 int64;
        27: v27 int64;
        28: v28 int64;
        29: v29 int64;
        30: v30 int64;
        31: v31 int64;
        32: v32 int64;
        33: v33 int64;
        34: v34 int64;
        35: v35 int64;
        36: v36 int64;
        37: v37 int64;
        38: v38 int64;
        39: v39 int64;
        40: v40 int64;
        41: v41 int64;
        42: v42 int64;
        43: v43 int64;
        44: v44 int64;
        45: v45 int64;
        46: v46 int64;
        47: v47 int64;
        48: v48 int64;
        49: v49 int64;
        50: v50 int64;
        51: v51 int64;
        52: v52 int64;
        53: v53 int64;
        54: v54 int64;
        55: v55 int64;
        56: v56 int64;
        57: v57 int64;
        58: v58 int64;
        59: v59 int64;
        60: v60 int64;
        61: v61 int64;
        62: v62 int64;
        63: v63 int64;
        // The 64th field of a table must be another table, otherwise it will cause
        // fi-0093: Max Ordinal In Table Must Be Table.
        64: v64 Table64thField;
        65: v65 int64;
    };

In order to allow growth beyond 64 ordinals, FIDL requires the last field of a
table to be another table. Any table fields beyond 64 must be placed in a nested
table.

> [!TIP]
> **Correct**

    library test.good.fi0092;

    type Table64thField = table {
        1: x int64;
        // Any fields beyond 64 of table Example must be move to the nested table in
        // ordinal 64 of Example.
        2: v65 int64;
    };

    type Example = table {
        1: v1 int64;
        2: v2 int64;
        3: v3 int64;
        4: v4 int64;
        5: v5 int64;
        6: v6 int64;
        7: v7 int64;
        8: v8 int64;
        9: v9 int64;
        10: v10 int64;
        11: v11 int64;
        12: v12 int64;
        13: v13 int64;
        14: v14 int64;
        15: v15 int64;
        16: v16 int64;
        17: v17 int64;
        18: v18 int64;
        19: v19 int64;
        20: v20 int64;
        21: v21 int64;
        22: v22 int64;
        23: v23 int64;
        24: v24 int64;
        25: v25 int64;
        26: v26 int64;
        27: v27 int64;
        28: v28 int64;
        29: v29 int64;
        30: v30 int64;
        31: v31 int64;
        32: v32 int64;
        33: v33 int64;
        34: v34 int64;
        35: v35 int64;
        36: v36 int64;
        37: v37 int64;
        38: v38 int64;
        39: v39 int64;
        40: v40 int64;
        41: v41 int64;
        42: v42 int64;
        43: v43 int64;
        44: v44 int64;
        45: v45 int64;
        46: v46 int64;
        47: v47 int64;
        48: v48 int64;
        49: v49 int64;
        50: v50 int64;
        51: v51 int64;
        52: v52 int64;
        53: v53 int64;
        54: v54 int64;
        55: v55 int64;
        56: v56 int64;
        57: v57 int64;
        58: v58 int64;
        59: v59 int64;
        60: v60 int64;
        61: v61 int64;
        62: v62 int64;
        63: v63 int64;
        64: v64 Table64thField;
    };

Every field in a table incurs the overhead of a FIDL envelope in order to allow
the field to be optional. This allows every field of a table to be present or
absent and enables tables to be evolved by adding or removing fields, but at the
cost of much greater memory overhead than structs.

In general you can both avoid this error and reduce overhead by avoiding having
small, granular fields in tables. Instead you can group together elements that
you expect will need to be added or removed simultaneously into structs and use
those as the fields of the table. This reduces overhead and avoid running out of
ordinals at the cost of some evolvability.

This became an error in [RFC-0132: FIDL table size
limit](https://fuchsia.dev/docs/contribute/governance/rfcs/0132_fidl_table_size_limit), which
was intended to prevent users from accidentally incurring the overhead of very
large tables. This extra cost isn't obvious in the schema, especially when there
are only a few fields (with large ordinals), or where there are many fields but
only a few are used at a time.

## fi-0093: Max ordinal in table must be table

The type of the 64th member in a FIDL table must itself be a table:

> [!WARNING]
> **Incorrect**

    library test.bad.fi0093;

    type Example = table {
        1: v1 int64;
        2: v2 int64;
        3: v3 int64;
        4: v4 int64;
        5: v5 int64;
        6: v6 int64;
        7: v7 int64;
        8: v8 int64;
        9: v9 int64;
        10: v10 int64;
        11: v11 int64;
        12: v12 int64;
        13: v13 int64;
        14: v14 int64;
        15: v15 int64;
        16: v16 int64;
        17: v17 int64;
        18: v18 int64;
        19: v19 int64;
        20: v20 int64;
        21: v21 int64;
        22: v22 int64;
        23: v23 int64;
        24: v24 int64;
        25: v25 int64;
        26: v26 int64;
        27: v27 int64;
        28: v28 int64;
        29: v29 int64;
        30: v30 int64;
        31: v31 int64;
        32: v32 int64;
        33: v33 int64;
        34: v34 int64;
        35: v35 int64;
        36: v36 int64;
        37: v37 int64;
        38: v38 int64;
        39: v39 int64;
        40: v40 int64;
        41: v41 int64;
        42: v42 int64;
        43: v43 int64;
        44: v44 int64;
        45: v45 int64;
        46: v46 int64;
        47: v47 int64;
        48: v48 int64;
        49: v49 int64;
        50: v50 int64;
        51: v51 int64;
        52: v52 int64;
        53: v53 int64;
        54: v54 int64;
        55: v55 int64;
        56: v56 int64;
        57: v57 int64;
        58: v58 int64;
        59: v59 int64;
        60: v60 int64;
        61: v61 int64;
        62: v62 int64;
        63: v63 int64;
        64: v64 int64;
    };

Users that find themselves needing to add a 64th member should create a separate
table to hold members 64 and beyond, and place that member in the table instead:

> [!TIP]
> **Correct**

    library test.good.fi0093;

    type Table64thField = table {
        1: x int64;
    };

    type Example = table {
        1: v1 int64;
        2: v2 int64;
        3: v3 int64;
        4: v4 int64;
        5: v5 int64;
        6: v6 int64;
        7: v7 int64;
        8: v8 int64;
        9: v9 int64;
        10: v10 int64;
        11: v11 int64;
        12: v12 int64;
        13: v13 int64;
        14: v14 int64;
        15: v15 int64;
        16: v16 int64;
        17: v17 int64;
        18: v18 int64;
        19: v19 int64;
        20: v20 int64;
        21: v21 int64;
        22: v22 int64;
        23: v23 int64;
        24: v24 int64;
        25: v25 int64;
        26: v26 int64;
        27: v27 int64;
        28: v28 int64;
        29: v29 int64;
        30: v30 int64;
        31: v31 int64;
        32: v32 int64;
        33: v33 int64;
        34: v34 int64;
        35: v35 int64;
        36: v36 int64;
        37: v37 int64;
        38: v38 int64;
        39: v39 int64;
        40: v40 int64;
        41: v41 int64;
        42: v42 int64;
        43: v43 int64;
        44: v44 int64;
        45: v45 int64;
        46: v46 int64;
        47: v47 int64;
        48: v48 int64;
        49: v49 int64;
        50: v50 int64;
        51: v51 int64;
        52: v52 int64;
        53: v53 int64;
        54: v54 int64;
        55: v55 int64;
        56: v56 int64;
        57: v57 int64;
        58: v58 int64;
        59: v59 int64;
        60: v60 int64;
        61: v61 int64;
        62: v62 int64;
        63: v63 int64;
        64: v64 Table64thField;
    };

The reasoning and motivations behind this requirement are fully elaborated in
[RFC-0132: FIDL table size limit](https://fuchsia.dev/docs/contribute/governance/rfcs/0132_fidl_table_size_limit). In short, FIDL tables need to have
relatively constrained limits on the number of fields that they allow, otherwise
the encoded form of a table that only uses a few fields at a time would have an
unacceptably large amount of dead space (16 bytes for every omitted member).

To give users who want more than 64 fields in their tables a workaround, FIDL
forces the last ordinal to be reserved for a "continuation table" that contains
the extra fields. Using any other type in this position would render the table
unextendable going forward.

## fi-0094: Duplicate table member ordinals

The ordinals used for members in a `table` declaration cannot be repeated:

> [!WARNING]
> **Incorrect**

    library test.bad.fi0094;

    type MyTable = table {
        1: my_field string;
        1: my_other_field uint32;
    };

Increment the ordinals as needed to ensure that the declaration has unique
ordinals for all of its members:

> [!TIP]
> **Correct**

    library test.good.fi0094a;

    type MyTable = table {
        1: my_field string;
        2: my_other_field uint32;
    };

Alternatively, one of the members with the duplicated name can be removed:

    library test.good.fi0094b;

    type MyTable = table {
        1: my_field string;
    };

The ordinal is used to identify the field on the wire. If two members share an
ordinal, there is no reliable way to tell which field is being referred to when
decoding a FIDL message.

## fi-0095

> [!WARNING]
> **Deprecated:** This error code has been retired.

## fi-0096

> [!WARNING]
> **Deprecated:** This error code has been retired.

## fi-0097: Duplicate union member ordinals

The ordinals used for members in a `union` declaration cannot be repeated:

> [!WARNING]
> **Incorrect**

    library test.bad.fi0097;

    type MyUnion = strict union {
        1: my_variant string;
        1: my_other_variant int32;
    };

Increment the ordinals as needed to ensure that the declaration has unique
ordinals for all of its members:

> [!TIP]
> **Correct**

    library test.good.fi0097a;

    type MyUnion = strict union {
        1: my_variant string;
        2: my_other_variant int32;
    };

Alternatively, one of the members with the duplicated name can be removed:

    library test.good.fi0097b;

    type MyUnion = strict union {
        1: my_variant string;
    };

The ordinal is used to identify the variant on the wire. If two members share an
ordinal, there is no reliable way to tell which variant is being referred to
when decoding a FIDL message.

## fi-0098

> [!WARNING]
> **Deprecated:** This error code has been retired.

## fi-0099

> [!WARNING]
> **Deprecated:** This error code has been retired.

## fi-0100

> [!WARNING]
> **Deprecated:** This error code has been retired.

## fi-0101: Unresolvable size constraint

The size constraint applied to a `vector` or `string` type definition must be a
valid value of the `uint32` type:

> [!WARNING]
> **Incorrect**

    library test.bad.fi0101a;

    alias MyBoundedOptionalVector = vector<uint32>:<"255", optional>;

    library test.bad.fi0101b;

    alias MyBoundedOptionalVector = vector<uint32>:<uint8, optional>;

Ensure that this is the case:

> [!TIP]
> **Correct**

    library test.good.fi0101;

    alias MyBoundedOptionalVector = vector<uint32>:<255, optional>;

## fi-0102: Unresolvable member value

The members of `bits` and `enum` declarations must be resolvable values of the
specified subtype:

> [!WARNING]
> **Incorrect**

    library test.bad.fi0102;

    type Fruit = bits : uint64 {
        ORANGE = 1;
        APPLE = 2;
        BANANA = -4;
    };

Ensure that all values match the underlying type of the declaration:

> [!TIP]
> **Correct**

    library test.good.fi0102;

    type Fruit = bits : uint64 {
        ORANGE = 1;
        APPLE = 2;
        BANANA = 4;
    };

## fi-0103: Unresolvable struct default value

The default values for the members of `struct` declarations must match their
respective member's stated type:

> [!WARNING]
> **Incorrect**

    library test.bad.fi0103;

    type MyEnum = enum : int32 {
        A = 1;
    };

    type MyStruct = struct {
        @allow_deprecated_struct_defaults
        field MyEnum = 1;
    };

Ensure that the value matches the declared type:

> [!TIP]
> **Correct**

    library test.good.fi0103;

    type MyEnum = enum : int32 {
        A = 1;
    };

    type MyStruct = struct {
        @allow_deprecated_struct_defaults
        field MyEnum = MyEnum.A;
    };

> [!NOTE]
> **Note:** Default `struct` members have been removed by [RFC-0160: Remove support
> for FIDL struct
> defaults](https://fuchsia.dev/docs/contribute/governance/rfcs/0160_fidl_remove_struct_defaults), and are currently deprecated, with no new uses cases being supported. See [fi-0050](https://fuchsia.dev/fuchsia-src/reference/fidl/language/errcat#fi-0050) for more information.

## fi-0104: Unresolvable attribute argument

Values of arguments for [official](https://fuchsia.dev/docs/reference/fidl/language/attributes)
FIDL attributes cannot be invalid per the attribute schema's expectation for
that argument:

> [!WARNING]
> **Incorrect**

    library test.bad.fi0104;

    type MyStruct = struct {
        my_field @generated_name(true) struct {};
    };

Ensure that the type of value being used as an attribute argument is correct:

> [!TIP]
> **Correct**

    library test.good.fi0104;

    type MyStruct = struct {
        my_field @generated_name("my_inner_type") struct {};
    };

## fi-0105

> [!WARNING]
> **Deprecated:** This error code has been retired.

## fi-0106

> [!WARNING]
> **Deprecated:** This error code has been retired.

## fi-0107: Duplicate member values

Neither `bits` nor `enum` declarations can have members with the same value:

> [!WARNING]
> **Incorrect**

    library test.bad.fi0107;

    type Fruit = flexible enum {
        ORANGE = 1;
        APPLE = 1;
    };

Change the member values to all be unique:

> [!TIP]
> **Correct**

    library test.good.fi0107a;

    type Fruit = flexible enum {
        ORANGE = 1;
        APPLE = 2;
    };

Alternatively, remove one of the duplicated members:

> [!TIP]
> **Correct**

    library test.good.fi0107b;

    type Fruit = flexible enum {
        ORANGE = 1;
    };

## fi-0108

> [!WARNING]
> **Deprecated:** This error code has been retired.

## fi-0109

> [!WARNING]
> **Deprecated:** This error code has been retired.

## fi-0110: Resource containing types must be marked resource

A type that includes a handle, either directly or through the transitive
inclusion of another handle-containing type, cannot be declared without that
type being specified as a `resource`:

> [!WARNING]
> **Incorrect**

    library test.bad.fi0110;

    using zx;

    type Foo = struct {
        handle zx.Handle;
    };

There are two possible solutions. The first is to annotate the offending
declaration with the resource modifier:

> [!TIP]
> **Correct**

    library test.good.fi0110a;

    using zx;

    type Foo = resource struct {
        handle zx.Handle;
    };

Alternatively, one could opt to remove the `resource`-including type completely,
thereby obviating the need for the modifier on the owning declaration:

> [!TIP]
> **Correct**

    library test.good.fi0110b;

    type Foo = struct {
        value uint32;
    };

The reasoning and motivations behind the addition of the `resource` modifier and
the "infectious" nature of the usage pattern enforced by this error can be found
in [RFC-0057: Default no handles](https://fuchsia.dev/docs/contribute/governance/rfcs/0057_default_no_handles).

## fi-0111: Inline size exceeds limit

FIDL types whose inline size is 64 KiB or more are not allowed:

> [!WARNING]
> **Incorrect**

    library test.bad.fi0111;

    type MyStruct = struct {
        numbers array<uint8, 65536>;
    };

Instead, make sure the type has an inline size less than 64 KiB. In this case,
we can adjust the array bound:

> [!TIP]
> **Correct**

    library test.good.fi0111;

    type MyStruct = struct {
        numbers array<uint8, 65535>;
    };

This limit exists for performance reasons. It means that encoders and decoders
can assume sizes and offsets fit in unsigned 16 bit integers.

You are unlikely to run into this in practice unless you use large arrays or
deeply nested structs. Most FIDL constructs (such as strings, vectors, tables,
and unions) use out-of-line storage, which does not count towards their
individual inline size.

## fi-0112: Service member is not a `client_end`

Service members are only allowed to be client ends, not any other type:

> [!WARNING]
> **Incorrect**

    library test.bad.fi0112;

    protocol Calculator {};

    service Service {
        calculator server_end:Calculator;
    };

To fix the error, make sure the member has the form `client_end:P` for some protocol `P`:

> [!TIP]
> **Correct**

    library test.good.fi0112;

    protocol Calculator {};

    service Service {
        calculator client_end:Calculator;
    };

A service is a collection of protocol instances, not a general purpose data
structure, so it would not make sense for one to allow arbitrary types.

## fi-0113: Mismatched transport in service

A FIDL service is not allowed to contain protocols using different transports:

> [!WARNING]
> **Incorrect**

    library test.bad.fi0113;

    protocol ChannelProtocol {};

    @transport("Driver")
    protocol DriverProtocol {};

    service SomeService {
        a client_end:ChannelProtocol;
        b client_end:DriverProtocol;
    };

Instead, use separate services for each transport:

> [!TIP]
> **Correct**

    library test.good.fi0113;

    protocol ChannelProtocol {};

    @transport("Driver")
    protocol DriverProtocol {};

    service ChannelService {
        protocol client_end:ChannelProtocol;
    };

    service DriverService {
        protocol client_end:DriverProtocol;
    };

Note that services are an unfinished feature in FIDL. They were originally
designed in [RFC-0041: Support for unifying serviceas and
devices](https://fuchsia.dev/docs/contribute/governance/rfcs/0041_unifying_services_devices).
See [https://fxbug.dev/42160684](https://bugs.fuchsia.dev/p/fuchsia/issues/detail?id=8035#c36)
for the status as of October 2022.

## fi-0114: Composed protocol is too open

A protocol cannot compose another protocol that is more open than itself:

> [!WARNING]
> **Incorrect**

    library test.bad.fi0114;

    open protocol Composed {};

    ajar protocol Composing {
        compose Composed;
    };

You can fix this by increasing the openness of the composing protocol, i.e.
changing it from `closed` to `ajar` or from `ajar` to `open`:

> [!TIP]
> **Correct**

    library test.good.fi0114a;

    open protocol Composed {};

    open protocol Composing {
        compose Composed;
    };

Alternatively, you can reduce the openness of the composed protocol, i.e. change
it from `open` to `ajar` or from `ajar` to `closed`:

> [!TIP]
> **Correct**

    library test.good.fi0114b;

    ajar protocol Composed {};

    ajar protocol Composing {
        compose Composed;
    };

This rule exists because the openness of a protocol restricts what kind of
methods it is allowed to contain. For example, an ajar protocol cannot contain
flexible two-way methods, but an open protocol can, so it's not safe for an ajar
protocol to compose an open protocol.

See [RFC-0138: Handling unknown
interactions](https://fuchsia.dev/docs/contribute/governance/rfcs/0138_handling_unknown_interactions)
for more information about protocol modifiers.

## fi-0115: Flexible two-way method in requires open protocol

Closed and ajar protocols are not allowed to contain flexible two-way methods:

> [!WARNING]
> **Incorrect**

    library test.bad.fi0115;

    ajar protocol Protocol {
        flexible Method() -> ();
    };

Instead, mark the two-way method `strict` instead of `flexible`:

> [!TIP]
> **Correct**

    library test.good.fi0115a;

    ajar protocol Protocol {
        strict Method() -> ();
    };

Alternatively, mark the protocol `open` instead of `closed` or `ajar`:

> [!TIP]
> **Correct**

    library test.good.fi0115b;

    open protocol Protocol {
        flexible Method() -> ();
    };

This error exists because the purpose of the `closed` (or `ajar`) modifier is to
make sure a method does not contain any flexible (two-way) methods. When first
creating a protocol, you should carefully think about whether it should be
closed, ajar, or open based on the evolvability properties you need from it.

See [RFC-0138: Handling unknown
interactions](https://fuchsia.dev/docs/contribute/governance/rfcs/0138_handling_unknown_interactions)
for more information about protocol modifiers.

## fi-0116: Flexible one-way method requires ajar or open protocol

Closed protocols are not allowed to contain flexible one-way methods:

> [!WARNING]
> **Incorrect**

    library test.bad.fi0116;

    closed protocol Protocol {
        flexible Method();
    };

Instead, mark the one-way method `strict` instead of `flexible`:

> [!TIP]
> **Correct**

    library test.good.fi0116;

    closed protocol Protocol {
        strict Method();
    };

Alternatively, mark the protocol `ajar` or `open` instead of `closed`:

> [!TIP]
> **Correct**

    library test.good.fi0116;

    ajar protocol Protocol {
        flexible Method();
    };

This error exists because the purpose of the `closed` modifier is to make sure a
method does not contain any flexible methods. When first creating a protocol,
you should carefully think about whether it should be closed, ajar, or open
based on the evolvability properties you need from it.

See [RFC-0138: Handling unknown
interactions](https://fuchsia.dev/docs/contribute/governance/rfcs/0138_handling_unknown_interactions)
for more information about protocol modifiers.

## fi-0117: Handle used in incompatible transport

Protocols can only refer to handles that are compatible with their transport.
For example, a protocol over the Zircon channel transport cannot refer to
Fuchsia Driver Framework handles:

> [!WARNING]
> **Incorrect**

    library test.bad.fi0117;

    using fdf;

    protocol Protocol {
        Method(resource struct {
            h fdf.handle;
        });
    };

Instead, use handles that are compatible with the protocol's transport:

> [!TIP]
> **Correct**

    library test.good.fi0117a;

    using zx;

    protocol Protocol {
        Method(resource struct {
            h zx.Handle;
        });
    };

Alternatively, change the transport of the protocol to match the handles:

> [!TIP]
> **Correct**

    library test.good.fi0117b;

    using fdf;

    @transport("Driver")
    protocol Protocol {
        Method(resource struct {
            h fdf.handle;
        });
    };

## fi-0118: Transport end used in incompatible transport

Protocols can only refer to transport ends (`client_end` and `server_end`) of
protocols over the same transport. For example, a protocol using the Syscall
transport cannot refer to a client end of a protocol using the Driver transport:

> [!WARNING]
> **Incorrect**

    library test.bad.fi0118;

    @transport("Driver")
    protocol DriverProtocol {};

    @transport("Syscall")
    protocol P {
        M(resource struct {
            s client_end:DriverProtocol;
        });
    };

To fix the error, remove the transport end member:

> [!TIP]
> **Correct**

    library test.good.fi0118;

    @transport("Driver")
    protocol DriverProtocol {};

    @transport("Syscall")
    protocol Protocol {
        M();
    };

## fi-0119

> [!WARNING]
> **Deprecated:** This error code has been retired.

## fi-0120: Invalid attribute placement

Some [official attributes](https://fuchsia.dev/docs/reference/fidl/language/attributes) are only
allowed in certain places. For example, the `@selector` attribute can only be
used on methods:

> [!WARNING]
> **Incorrect**

    library test.bad.fi0120a;

    @selector("Nonsense")
    type MyUnion = union {
        1: hello uint8;
    };

To fix the error, remove the attribute:

> [!TIP]
> **Correct**

    library test.good.fi0120a;

    type MyUnion = union {
        1: hello uint8;
    };

You might also encounter this error when intending to use an attribute in a way
that is supported, but placing it in the wrong spot. For example, the
`@generated_name` attribute cannot go directly on a member:

> [!WARNING]
> **Incorrect**

    library test.bad.fi0120a;

    @selector("Nonsense")
    type MyUnion = union {
        1: hello uint8;
    };

Instead, it should go just before the member's anonymous layout:

> [!TIP]
> **Correct**

    library test.good.fi0120a;

    type MyUnion = union {
        1: hello uint8;
    };

## fi-0121: Deprecated attribute

Some [official attributes](https://fuchsia.dev/docs/reference/fidl/language/attributes) are
deprecated and should no longer be used:

> [!WARNING]
> **Incorrect**

    library test.bad.fi0121;

    @example_deprecated_attribute
    type MyStruct = struct {};

The fix depends on why the attribute was deprecated. For example, the error message might say to use a different attribute instead. In this case, we can just remove the attribute:

> [!TIP]
> **Correct**

    library test.good.fi0121;

    type MyStruct = struct {};

## fi-0122: Duplicate attribute name

An element cannot have multiple attributes with the same name:

> [!WARNING]
> **Incorrect**

    library test.bad.fi0122;

    @custom_attribute("first")
    @custom_attribute("second")
    type Foo = struct {};

Instead, specify each attribute only once:

> [!TIP]
> **Correct**

    library test.good.fi0122;

    @custom_attribute("first")
    type Foo = struct {};

## fi-0123: Duplicate canonical attribute name

An element cannot have multiple attributes with the same canonical name:

> [!WARNING]
> **Incorrect**

    library test.bad.fi0123;

    @custom_attribute("first")
    @CustomAttribute("second")
    type Foo = struct {};

Even though `custom_attribute` and `CustomAttribute` look different, they are
both represented by the **canonical** name `custom_attribute`. You get the
canonical name by converting the original name to `snake_case`.

To fix the error, give each attribute a name that is unique after
canonicalization.

> [!TIP]
> **Correct**

    library test.good.fi0123;

    @custom_attribute("first")
    @AnotherCustomAttribute("first")
    type Foo = struct {};

See [fi-0035](https://fuchsia.dev/fuchsia-src/reference/fidl/language/errcat#fi-0035) for more details on why FIDL requires declarations to
have unique canonical names.

## fi-0124: Custom attribute argument must be string or bool

The arguments on user-defined FIDL attributes are limited to being string or
boolean types:

> [!WARNING]
> **Incorrect**

    library test.bad.fi0124;

    @my_custom_attr(foo=1, bar=2.3)
    type MyStruct = struct {};

> [!TIP]
> **Correct**

    library test.good.fi0124;

    @my_custom_attr(foo=true, bar="baz")
    type MyStruct = struct {};

Unlike [official attributes](https://fuchsia.dev/docs/reference/fidl/language/attributes), the schema of user defined
attributes is not known to the compiler. Because of this, it is impossible for
the compiler to deduce the type of any given numeric argument - is `2` an
`int8`, a `uint64`, or a `float32`? There's no way for the compiler to know.

A possible solution to this problem would be to implement a first-class
`numeric` type in the JSON IR for ambiguous cases like these. However, because
custom attribute arguments are the only known use case for this today, this
feature has not been prioritized.

## fi-0125: Attribute argument must not be named

When using an [official attribute](https://fuchsia.dev/docs/reference/fidl/language/attributes)
that takes a single argument, you cannot name that argument:

> [!WARNING]
> **Incorrect**

    library test.bad.fi0125;

    @transport(value="Driver")
    protocol Foo {};

Instead, pass the argument without giving it a name:

> [!TIP]
> **Correct**

    library test.good.fi0125;

    @discoverable(name="example.Bar")
    protocol Foo {};

FIDL enforces this to make attributes more concise and consistent. Under the
hood, the argument name is inferred to be `value` (and this will show up in the
JSON IR) because that is the only argument the attribute takes.

## fi-0126: Attribute argument must be named

When using an [official attribute](https://fuchsia.dev/docs/reference/fidl/language/attributes)
that takes multiple arguments, you cannot pass an unnamed argument:

> [!WARNING]
> **Incorrect**

    @available(1)
    library test.bad.fi0126;

Instead, specify the name of the argument:

> [!TIP]
> **Correct**

    @available(added=1)
    library test.good.fi0126;

This error occurs because there is no way of knowing what argument you intended
to set if the attribute accepts more than one argument.

## fi-0127: Missing required attribute argument

When using an [official attribute](https://fuchsia.dev/docs/reference/fidl/language/attributes)
that has a required argument, you cannot omit it:

> [!WARNING]
> **Incorrect**

    library test.bad.fi0127;

    @has_required_arg
    type Foo = struct {};

Instead, provide the required argument:

> [!TIP]
> **Correct**

    library test.good.fi0127;

    @has_required_arg(required="something")
    type Foo = struct {};

## fi-0128: Missing single attribute argument

When using an [official attribute](https://fuchsia.dev/docs/reference/fidl/language/attributes)
that requires a single argument, you cannot omit it:

> [!WARNING]
> **Incorrect**

    library test.bad.fi0128;

    @transport
    protocol Protocol {};

Instead, provide an argument:

> [!TIP]
> **Correct**

    library test.good.fi0128;

    @transport("Driver")
    protocol Protocol {};

## fi-0129: Unknown attribute argument

When using an [official attribute](https://fuchsia.dev/docs/reference/fidl/language/attributes),
you cannot provide an argument that is not in its schema:

> [!WARNING]
> **Incorrect**

    @available(added=1, discontinued=2)
    library test.bad.fi0129;

If you meant to pass a different argument and got the name wrong, change it to use the correct name:

> [!TIP]
> **Correct**

    @available(added=1, deprecated=2)
    library test.good.fi0129a;

Alternatively, remove the argument:

> [!TIP]
> **Correct**

    @available(added=1)
    library test.good.fi0129b;

This error occurs because official attributes are validated against a schema. If
FIDL allowed arbitrary arguments, they would have no effect, and it could cause
bugs by masking typos.

## fi-0130: Duplicate attribute argument

An attribute cannot have two arguments with the same name:

> [!WARNING]
> **Incorrect**

    library test.bad.fi0130;

    @custom_attribute(custom_arg=true, custom_arg=true)
    type Foo = struct {};

Instead, only provide one argument with that name:

> [!TIP]
> **Correct**

    library test.good.fi0130;

    @custom_attribute(custom_arg=true)
    type Foo = struct {};

## fi-0131: Duplicate canonical attribute argument

An attribute cannot have two arguments with the same canonical name:

> [!WARNING]
> **Incorrect**

    library test.bad.fi0131;

    @custom_attribute(custom_arg=true, CustomArg=true)
    type Foo = struct {};

Even though `custom_arg` and `CustomArg` look different, they are both
represented by the **canonical** name `custom_arg`. You get the canonical name
by converting the original name to `snake_case`.

To fix the error, give each argument a name that is unique after
canonicalization:

> [!TIP]
> **Correct**

    library test.good.fi0131a;

    @custom_attribute(custom_arg=true, AnotherCustomArg=true)
    type Foo = struct {};

Alternatively, remove one of the arguments:

> [!TIP]
> **Correct**

    library test.good.fi0131b;

    @custom_attribute(custom_arg=true)
    type Foo = struct {};

See [fi-0035](https://fuchsia.dev/fuchsia-src/reference/fidl/language/errcat#fi-0035) for more details on why FIDL requires declarations to
have unique canonical names.

## fi-0132: Unexpected attribute argument

When using an [official attribute](https://fuchsia.dev/docs/reference/fidl/language/attributes)
that takes no arguments, you cannot provide an argument:

> [!WARNING]
> **Incorrect**

    library test.bad.fi0132;

    type Foo = flexible enum : uint8 {
        @unknown("hello")
        BAR = 1;
    };

Instead, remove the argument:

> [!TIP]
> **Correct**

    library test.good.fi0132;

    type Foo = flexible enum : uint8 {
        @unknown
        BAR = 1;
    };

## fi-0133: Attribute argument must be literal

Certain [official attributes](https://fuchsia.dev/docs/reference/fidl/language/attributes) do
not allow arguments that are references to constants:

> [!WARNING]
> **Incorrect**

    library test.bad.fi0133;

    const NAME string = "MyTable";

    type Foo = struct {
        bar @generated_name(NAME) table {};
    };

Instead, pass a literal value as the argument:

> [!TIP]
> **Correct**

    library test.good.fi0133;

    type Foo = struct {
        bar @generated_name("MyTable") table {};
    };

These attributes require a literal argument because their values influence
compilation. Supporting non-literal arguments would be difficult to implement,
or in some cases impossible because it leads to contradictions.

## fi-0134

> [!WARNING]
> **Deprecated:** This error code has been retired.

## fi-0135: Invalid discoverable name

This error occurs when you use a bad name for an `@discoverable` attribute.
`@discoverable` attributes should be the library name followed by a `.` and the
protocol name.

> [!WARNING]
> **Incorrect**

    library test.bad.fi0135;

    @discoverable(name="test.bad.fi0135/Parser")
    protocol Parser {
        Tokenize() -> (struct {
            tokens vector<string>;
        });
    };

To fix this error, use a valid discoverable name:

> [!TIP]
> **Correct**

    library test.good.fi0135;

    @discoverable(name="test.good.fi0135.Parser")
    protocol Parser {
        Tokenize() -> (struct {
            tokens vector<string>;
        });
    };

## fi-0136

> [!WARNING]
> **Deprecated:** This error code has been retired.

## fi-0137

> [!WARNING]
> **Deprecated:** This error code has been retired.

## fi-0138

> [!WARNING]
> **Deprecated:** This error code has been retired.

## fi-0139

> [!WARNING]
> **Deprecated:** This error code has been retired.

## fi-0140

> [!WARNING]
> **Deprecated:** This error code has been retired.

## fi-0141: Invalid error type

The `error` type on a method response payload must be an `int32`, `uint32`, or
`enum` thereof:

> [!WARNING]
> **Incorrect**

    library test.bad.fi0141;

    protocol MyProtocol {
        MyMethod() -> () error float32;
    };

Change the `error` type to one of the valid options to fix this error:

> [!TIP]
> **Correct**

    library test.good.fi0141;

    protocol MyProtocol {
        MyMethod() -> () error int32;
    };

See [RFC-0060: Error handling](https://fuchsia.dev/docs/contribute/governance/rfcs/0050_syntax_revamp) for more details.

## fi-0142: Invalid protocol transport type

The `@transport(...)` attribute on a `protocol` declaration must not specify an
invalid transport:

> [!WARNING]
> **Incorrect**

    library test.bad.fi0142;

    @transport("Invalid")
    protocol MyProtocol {
        MyMethod();
    };

Use one of the supported transports instead:

> [!TIP]
> **Correct**

    library test.good.fi0142;

    @transport("Syscall")
    protocol MyProtocol {
        MyMethod();
    };

What constitutes a supported transport is still being finalized. See the [FIDL
attributes](https://fuchsia.dev/docs/reference/fidl/language/attributes#transport) for the latest information.

## fi-0143

> [!WARNING]
> **Deprecated:** This error code has been retired.

## fi-0144

> [!WARNING]
> **Deprecated:** This error code has been retired.

## fi-0145: Attribute typo

An attribute name whose spelling is too similar to one of FIDL's official
[attributes](https://fuchsia.dev/docs/reference/fidl/language/attributes) will result in a compiler warning:

> [!WARNING]
> **Incorrect**

    library test.bad.fi0145;

    @duc("should be doc")
    protocol Example {
        Method();
    };

In the above example, the attribute `@duc` is too similar in spelling to the
official FIDL attribute `@doc`. In cases like this, the attribute naming is
intentional, and not an accidental misspelling of an official FIDL attribute, it
should be modified to be sufficiently unique:

> [!TIP]
> **Correct**

    library test.good.fi0145;

    @duck("quack")
    protocol Example {
        Method();
    };

Besides spell checking, the purpose of this warning is to discourage using
names that are too similar to official FIDL attributes.

The typo detection algorithm works by calculating the [edit
distance](https://en.wikipedia.org/wiki/Edit_distance) of the attribute name from every official FIDL
attribute. Names that are too similar, defined as having too small of an edit
distance, trigger the typo detector.

## fi-0146: Invalid generated name

This error occurs when you use the `@generated_name` attribute with an invalid
name. Generated names must follow the same rules as all FIDL identifiers.

> [!WARNING]
> **Incorrect**

    library test.bad.fi0146;

    type Device = table {
        1: kind flexible enum {
            DESKTOP = 1;
            PHONE = 2;
        };
    };

    type Input = table {
        1: kind @generated_name("_kind") flexible enum {
            KEYBOARD = 1;
            MOUSE = 2;
        };
    };

To fix this issue, change the `@generated_name` value to a valid identifier.

> [!TIP]
> **Correct**

    library test.good.fi0146;

    type Device = table {
        1: kind flexible enum {
            DESKTOP = 1;
            PHONE = 2;
        };
    };

    type Input = table {
        1: kind @generated_name("input_kind") flexible enum {
            KEYBOARD = 1;
            MOUSE = 2;
        };
    };

## fi-0147: `@available` missing arguments

This error occurs when you use the `@available` attribute and don't provide the
necessary arguments. `@available` requires at least one of `added`,
`deprecated`, or `removed`.

> [!WARNING]
> **Incorrect**

    @available(added=1)
    library test.bad.fi0147;

    @available
    type Foo = struct {};

To fix this issue, add one of the required arguments:

> [!TIP]
> **Correct**

    @available(added=1)
    library test.good.fi0147;

    @available(added=2)
    type Foo = struct {};

See [FIDL versioning](https://fuchsia.dev/docs/reference/fidl/language/versioning) for more information.

## fi-0148: Note without deprecation

This errors occurs when you use the `note` argument for the `@available`
attribute without the `deprecated` argument. `note`s are only supported for
deprecation.

> [!WARNING]
> **Incorrect**

    @available(added=1, note="My note")
    library test.bad.fi0148;

To fix this error, either remove the note:

> [!TIP]
> **Correct**

    @available(added=1)
    library test.good.fi0148a;

or add the necessary `deprecated` notice:

    @available(added=1, deprecated=2, note="Removed in 2; use X instead.")
    library test.good.fi0148b;

See [FIDL versioning](https://fuchsia.dev/docs/reference/fidl/language/versioning) for more information.

## fi-0149: Platform not on library

This error occurs when you try to use the `@available` attribute's `platform`
argument anywhere other than above a library declaration. The `platform`
argument is only valid at the `library` level.

> [!WARNING]
> **Incorrect**

    @available(added=1)
    library test.bad.fi0149;

    @available(platform="foo")
    type Person = struct {
        name string;
    };

To fix this, either move the `platform` argument to the library `@available`
attribute:

> [!TIP]
> **Correct**

    @available(added=1, platform="foo")
    library test.good.fi0149a;

    type Person = struct {
        name string;
    };

or remove the `platform` argument completely:

    @available(added=1)
    library test.good.fi0149b;

    type Person = struct {
        name string;
    };

## fi-0150: Library availability missing added

This error occurs when you add an `@available` attribute to your library without
providing an `added` argument. The `added` argument is required for `library`
`@available` attributes.

> [!WARNING]
> **Incorrect**

    @available(removed=2)
    library test.bad.fi0150a;

    @available(platform="foo")
    library test.bad.fi0150b;

To fix this issue, add the `added` argument to the library's `@available`
attribute:

> [!TIP]
> **Correct**

    @available(added=1, removed=2)
    library test.good.fi0150a;

    @available(added=1, platform="foo")
    library test.good.fi0150b;

## fi-0151: Missing library availability

This error occurs when you add an `@available` attribute on a non-`library`
declaration without an `@available` attribute on the `library` declaration.

> [!WARNING]
> **Incorrect**

    library test.bad.fi0151;

    @available(added=1)
    type Person = struct {
        name string;
    };

To fix this error, add the `@available` attribute to the `library` declaration:

> [!TIP]
> **Correct**

    @available(added=1)
    library test.good.fi0151a;

    @available(added=1)
    type Person = struct {
        name string;
    };

or remove the `@available` attribute from the non`library` declaration:

    library test.good.fi0151b;

    type Person = struct {
        name string;
    };

## fi-0152: Invalid platform

This error occurs when you use invalid characters for the `platform` argument of
an `@available` attribute. The `platform` argument must be a valid [FIDL library
identifier](https://fuchsia.dev/docs/reference/fidl/language/language#identifiers).

> [!WARNING]
> **Incorrect**

    @available(added=1, platform="Spaces are not allowed")
    library test.bad.fi0152;

To fix this error, remove the disallowed characters:

> [!TIP]
> **Correct**

    @available(added=1, platform="foo")
    library test.good.fi0152;

## fi-0153: Invalid version

This error occurs when you use an invalid version for an `added` or `removed`
argument on an `@available` attribute. `added` and `removed` arguments must be
positive integers between 1 and 2\^63-1, or the special constant `HEAD`.

> [!WARNING]
> **Incorrect**

    @available(added=0)
    library test.bad.fi0153;

To fix this issue, change the version to a valid value:

> [!TIP]
> **Correct**

    @available(added=1)
    library test.good.fi0153;

## fi-0154: Invalid availability order

This error occurs when you use a bad combination of `added`, `deprecated`, and
`remove` arguments for an `@available` attribute. The following constraints must
be respected:

- `added` must be less than or equal to `deprecated`
- `deprecated` must be less than `removed`
- `added` must be less than `removed`

> [!WARNING]
> **Incorrect**

    @available(added=2, removed=2)
    library test.bad.fi0154a;

    @available(added=2, deprecated=3, removed=3)
    library test.bad.fi0154b;

To fix this issue update the `added`, `deprecated`, and `removed` arguments to
the required ordering:

> [!TIP]
> **Correct**

    @available(added=1, removed=2)
    library test.good.fi0154a;

    @available(added=2, deprecated=2, removed=3)
    library test.good.fi0154b;

## fi-0155: Availability conflicts with parent

This error occurs when you add an `@availability` attribute to a non-`library`
declaration that conflicts with the `library`'s declaration.

> [!WARNING]
> **Incorrect**

    @available(added=2, deprecated=3, removed=4)
    library test.bad.fi0155a;

    @available(added=1)
    type Person = struct {
        name string;
    };

    @available(added=2, deprecated=3, removed=4)
    library test.bad.fi0155b;

    @available(added=4)
    type Person = struct {
        name string;
    };

To fix this error, update the `@availability` attributes to the required
constraints:

> [!TIP]
> **Correct**

    @available(added=2, deprecated=3, removed=4)
    library test.good.fi0155;

    @available(added=2)
    type Person = struct {
        name string;
    };

## fi-0156: Cannot be optional

This error occurs when you try to mark a type as optional that cannot be
optional.

> [!WARNING]
> **Incorrect**

    library test.bad.fi0156;

    type Person = struct {
        name string;
        age int16:optional;
    };

To fix this error, remove the optional constraint:

> [!TIP]
> **Correct**

    library test.good.fi0156;

    type Person = struct {
        name string;
        age int16;
    };

Only FIDL types that can be made optional with no change to the wire shape are
allowed to use the `optional` constraint. See the
[optionality](https://fuchsia.dev/docs/development/languages/fidl/examples/README#optionality) guide, or the expandable below, for more information.

#### FIDL recipe: Optionality

Certain FIDL types can be made *optional* with no change to the wire shape of
their containing message with the addition of the `:optional` constraint.
Further, the `table` layout is always optional, while the `struct` layout never
is. To make a `struct` optional, it must be wrapped in a `box<T>`, thereby
changing the wire shape of its containing message.

| Base type | Optional version | Does optionality change the wire layout? |
|---|---|---|
| `struct {...}` | `box<struct {...}>` | Yes |
| `table {...}` | `table {...}` | No |
| `union {...}` | `union {...}:optional` | No |
| `vector<T>` | `vector<T>:optional` | No |
| `string` | `string:optional` | No |
| `zx.Handle` | `zx.Handle:optional` | No |
| `client_end:P` | `client_end:<P, optional>` | No |
| `server_end:P` | `server_end:<P, optional>` | No |

All other types (`bits`, `enum`, `array<T, N>`, and the primitive types) cannot
be made optional.

> [!CAUTION]
> **Caution:** This example implementation builds on the [key-value store baseline
> example](https://fuchsia.dev/docs/development/languages/fidl/examples/key_value_store#baseline) as a prerequisite. You can see more information about setting up the extended base case in this document.

In this variant, we allow our key-value store to take other key-value stores as
members. In short, we turn it into a tree. We do this by replacing the original
definition of `value` with one that utilizes a two-member `union`: one variant
stores leaf nodes using the same `vector<byte>` type as before, while the other
stores branch nodes in the form of other nested stores.

### Reasoning

Here, we see several uses of *optionality*, whereby we can declare a type that
may or may not exist. There are three flavors of optionality in FIDL:

- Types that have are always stored [out-of-line](https://fuchsia.dev/docs/reference/fidl/language/wire-format#primary_and_secondary_objects) on the wire, and thus have a builtin way to describe "absentness" via the [null envelope](https://fuchsia.dev/docs/reference/fidl/language/wire-format#envelopes). Enabling optionality for these types doesn't affect the wire shape of messages they are included in - it simply changes which values are valid for that particular type. The `union`, `vector<T>`, `client_end`, `server_end`, and `zx.Handle` types can all be made optional via the addition of the `:optional` constraint. By making our `value` `union` optional, we are able to introduce a canonical "null" entry, in the form of an absent `value`. This means that empty `bytes` and absent/empty `store` properties are invalid values.
- Unlike the aforementioned types, the `struct` layout has no extra space where a null header can be stored. Because of this, it needs to be wrapped in an envelope, changing the on-the-wire shape of the message it is being included in. To ensure that this wire-modifying effect easily legible, the `Item` `struct` type must be wrapped in a `box<T>` type template.
- Finally, `table` layouts are always optional. An absent `table` is simply one with none of its members set.

Trees are a naturally self-referential data structure: any node in the tree may
contain a leaf with pure data (in this case, a string), or a sub-tree with more
nodes. This requires recursion: the definition of `Item` is now transitively
dependent on itself! Representing *recursive types* in FIDL can be a bit tricky,
especially because support is currently [somewhat
limited](https://fxbug.dev/42110612). We can support such types as long as there is
at least one optional type in the cycle created by the self-reference. For
instance, here we define the `items` `struct` member to be a `box<Item>`,
thereby breaking the includes cycle.

These changes also make heavy use of *anonymous types* , or types whose
declarations are inlined at their sole point of use, rather than being named,
top-level `type` declarations of their own. By default, the names of anonymous
types in the generated language bindings are taken from their local context. For
instance, the newly introduced `flexible union` takes on its owning member's
name `Value`, the newly introduced `struct` would become `Store`, and so on.
Because this heuristic can sometimes cause collisions, FIDL provides an escape
hatch by allowing the author to manually override an anonymous type's *generated
name* . This is done via the `@generated_name` attribute, which allows one to
change the name generated by backends. We can use one here, where the would-be
`Store` type is renamed to `NestedStore` to prevent a name collision with the
`protocol` declaration that uses that same name.

### Implementation

> [!NOTE]
> **Note:** The source code for this example is located at [//examples/fidl/new/key_value_store/support_trees](https://cs.opensource.google/fuchsia/fuchsia/+/main:/examples/fidl/new/key_value_store/support_trees). This directory includes tests exercising the implementation in all supported languages, which may be run locally by executing the following from the command line: `fx set core.x64 --with=//examples/fidl/new:tests && fx test
> keyvaluestore_supporttrees`.

The FIDL, CML, and realm interface definitions are modified as follows:

### FIDL

```
// Copyright 2022 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
library examples.keyvaluestore.supporttrees;

/// An item in the store. The key must match the regex `^[A-z][A-z0-9_\.\/]{2,62}[A-z0-9]$`. That
/// is, it must start with a letter, end with a letter or number, contain only letters, numbers,
/// periods, and slashes, and be between 4 and 64 characters long.
type Item = struct {
    key string:128;
    value strict union {
        // Keep the original `bytes` as one of the options in the new union. All leaf nodes in the
        // tree must be `bytes`, or absent unions (representing empty). Empty byte arrays are
        // disallowed.
        1: bytes vector<byte>:64000;

        // Allows a store within a store, thereby turning our flat key-value store into a tree
        // thereof. Note the use of `@generated_name` to prevent a type-name collision with the
        // `Store` protocol below, and the use of `box<T>` to ensure that there is a break in the
        // chain of recursion, thereby allowing `Item` to include itself in its own definition.
        //
        // This is a table so that added fields, like for example a `hash`, can be easily added in
        // the future.
        2: store @generated_name("nested_store") table {
            1: items vector<box<Item>>;
        };
    }:optional;
};

/// An enumeration of things that may go wrong when trying to write a value to our store.
type WriteError = flexible enum {
    UNKNOWN = 0;
    INVALID_KEY = 1;
    INVALID_VALUE = 2;
    ALREADY_EXISTS = 3;
};

/// A very basic key-value store.
@discoverable
open protocol Store {
    /// Writes an item to the store.
    flexible WriteItem(struct {
        attempt Item;
    }) -> () error WriteError;
};
```

### CML

### Client

```
// Copyright 2022 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
{
    include: [ "syslog/client.shard.cml" ],
    program: {
        runner: "elf",
        binary: "bin/client_bin",
    },
    use: [
        { protocol: "examples.keyvaluestore.supporttrees.Store" },
        {
            config: "fuchsia.examples.keyvaluestore.supporttrees.WriteItems",
            key: "write_items",
            type: "vector",
            max_count: 16,
            element: {
                type: "string",
                max_size: 64,
            },
            availability: "transitional",
            default: [],
        },

        // A newline separated list nested entries. The first line should be the key
        // for the nested store, and each subsequent entry should be a pointer to a text file
        // containing the string value. The name of that text file (without the `.txt` suffix) will
        // serve as the entries key.
        {
            config: "fuchsia.examples.keyvaluestore.supporttrees.WriteNested",
            key: "write_nested",
            type: "vector",
            max_count: 16,
            element: {
                type: "string",
                max_size: 64,
            },
            availability: "transitional",
            default: [],
        },

        // A list of keys, all of which will be populated as null entries.
        {
            config: "fuchsia.examples.keyvaluestore.supporttrees.WriteNull",
            key: "write_null",
            type: "vector",
            max_count: 16,
            element: {
                type: "string",
                max_size: 64,
            },
            availability: "transitional",
            default: [],
        },

    ],
}
```

### Server

```
// Copyright 2022 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
{
    include: [ "syslog/client.shard.cml" ],
    program: {
        runner: "elf",
        binary: "bin/server_bin",
    },
    capabilities: [
        { protocol: "examples.keyvaluestore.supporttrees.Store" },
    ],
    expose: [
        {
            protocol: "examples.keyvaluestore.supporttrees.Store",
            from: "self",
        },
    ],
}
```

### Realm

```
// Copyright 2022 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
{
    children: [
        {
            name: "client",
            url: "#meta/client.cm",
        },
        {
            name: "server",
            url: "#meta/server.cm",
        },
    ],
    offer: [
        // Route the protocol under test from the server to the client.
        {
            protocol: "examples.keyvaluestore.supporttrees.Store",
            from: "#server",
            to: "#client",
        },

        // Route diagnostics support to all children.
        {
            dictionary: "diagnostics",
            from: "parent",
            to: [
                "#client",
                "#server",
            ],
        },
    ],
}
```

Client and server implementations can then be written in any supported language:

### Rust

### Client

```rust
// Copyright 2022 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

use {
    anyhow::{Context as _, Error},
    config::Config,
    fidl_examples_keyvaluestore_supporttrees::{Item, NestedStore, StoreMarker, Value},
    fuchsia_component::client::connect_to_protocol,
    std::{thread, time},
};

#[fuchsia::main]
async fn main() -> Result<(), Error> {
    println!("Started");

    // Load the structured config values passed to this component at startup.
    let config = Config::take_from_startup_handle();

    // Use the Component Framework runtime to connect to the newly spun up server component. We wrap
    // our retained client end in a proxy object that lets us asynchronously send `Store` requests
    // across the channel.
    let store = connect_to_protocol::<StoreMarker>()?;
    println!("Outgoing connection enabled");

    // This client's structured config has one parameter, a vector of strings. Each string is the
    // path to a resource file whose filename is a key and whose contents are a value. We iterate
    // over them and try to write each key-value pair to the remote store.
    for key in config.write_items.into_iter() {
        let path = format!("/pkg/data/{}.txt", key);
        let value = std::fs::read_to_string(path.clone())
            .with_context(|| format!("Failed to load {path}"))?;
        let res = store
            .write_item(&Item {
                key: key.clone(),
                value: Some(Box::new(Value::Bytes(value.into_bytes()))),
            })
            .await;
        match res? {
            Ok(_) => println!("WriteItem Success at key: {}", key),
            Err(err) => println!("WriteItem Error: {}", err.into_primitive()),
        }
    }

    // Add nested entries to the key-value store as well. The entries are strings, where the first
    // line is the key of the entry, and each subsequent entry should be a pointer to a text file
    // containing the string value. The name of that text file (without the `.txt` suffix) will
    // serve as the entries key.
    for spec in config.write_nested.into_iter() {
        let mut items = vec![];
        let mut nested_store = NestedStore::default();
        let mut lines = spec.split("\n");
        let key = lines.next().unwrap();

        // For each entry, make a new entry in the `NestedStore` being built.
        for entry in lines {
            let path = format!("/pkg/data/{}.txt", entry);
            let contents = std::fs::read_to_string(path.clone())
                .with_context(|| format!("Failed to load {path}"))?;
            items.push(Some(Box::new(Item {
                key: entry.to_string(),
                value: Some(Box::new(Value::Bytes(contents.into()))),
            })));
        }
        nested_store.items = Some(items);

        // Send the `NestedStore`, represented as a vector of values.
        let res = store
            .write_item(&Item {
                key: key.to_string(),
                value: Some(Box::new(Value::Store(nested_store))),
            })
            .await;
        match res? {
            Ok(_) => println!("WriteItem Success at key: {}", key),
            Err(err) => println!("WriteItem Error: {}", err.into_primitive()),
        }
    }

    // Each entry in this list is a null value in the store.
    for key in config.write_null.into_iter() {
        match store.write_item(&Item { key: key.to_string(), value: None }).await? {
            Ok(_) => println!("WriteItem Success at key: {}", key),
            Err(err) => println!("WriteItem Error: {}", err.into_primitive()),
        }
    }

    // TODO(https://fxbug.dev/42156498): We need to sleep here to make sure all logs get drained. Once the
    // referenced bug has been resolved, we can remove the sleep.
    thread::sleep(time::Duration::from_secs(2));
    Ok(())
}
```

### Server

```rust
// Copyright 2022 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

// Note: For the clarity of this example, allow code to be unused.
#![allow(dead_code)]

use {
    anyhow::{Context as _, Error},
    fidl_examples_keyvaluestore_supporttrees::{
        Item, StoreRequest, StoreRequestStream, Value, WriteError,
    },
    fuchsia_component::server::ServiceFs,
    futures::prelude::*,
    regex::Regex,
    std::cell::RefCell,
    std::collections::HashMap,
    std::collections::hash_map::Entry,
    std::str::from_utf8,
    std::sync::LazyLock,
};

static KEY_VALIDATION_REGEX: LazyLock<Regex> = LazyLock::new(|| {
    Regex::new(r"^[A-Za-z]\w+[A-Za-z0-9]$").expect("Key validation regex failed to compile")
});

// A representation of a key-value store that can contain an arbitrarily deep nesting of other
// key-value stores.
#[allow(clippy::box_collection, reason = "mass allow for https://fxbug.dev/381896734")]
enum StoreNode {
    Leaf(Option<Vec<u8>>),
    Branch(Box<HashMap<String, StoreNode>>),
}

/// Recursive item writer, which takes a `StoreNode` that may not necessarily be the root node, and
/// writes an entry to it.
fn write_item(
    store: &mut HashMap<String, StoreNode>,
    attempt: Item,
    path: &str,
) -> Result<(), WriteError> {
    // Validate the key.
    if !KEY_VALIDATION_REGEX.is_match(attempt.key.as_str()) {
        println!("Write error: INVALID_KEY, For key: {}", attempt.key);
        return Err(WriteError::InvalidKey);
    }

    // Write to the store, validating that the key did not already exist.
    match store.entry(attempt.key) {
        Entry::Occupied(entry) => {
            println!("Write error: ALREADY_EXISTS, For key: {}", entry.key());
            Err(WriteError::AlreadyExists)
        }
        Entry::Vacant(entry) => {
            let key = format!("{}{}", path, entry.key());
            match attempt.value {
                // Null entries are allowed.
                None => {
                    println!("Wrote value: NONE at key: {}", key);
                    entry.insert(StoreNode::Leaf(None));
                }
                Some(value) => match *value {
                    // If this is a nested store, recursively make a new store to insert at this
                    // position.
                    Value::Store(entry_list) => {
                        // Validate the value - absent stores, items lists with no children, or any
                        // of the elements within that list being empty boxes, are all not allowed.
                        if entry_list.items.is_some() {
                            let items = entry_list.items.unwrap();
                            if !items.is_empty() && items.iter().all(|i| i.is_some()) {
                                let nested_path = format!("{}/", key);
                                let mut nested_store = HashMap::<String, StoreNode>::new();
                                for item in items.into_iter() {
                                    write_item(&mut nested_store, *item.unwrap(), &nested_path)?;
                                }

                                println!("Created branch at key: {}", key);
                                entry.insert(StoreNode::Branch(Box::new(nested_store)));
                                return Ok(());
                            }
                        }

                        println!("Write error: INVALID_VALUE, For key: {}", key);
                        return Err(WriteError::InvalidValue);
                    }

                    // This is a simple leaf node on this branch.
                    Value::Bytes(value) => {
                        // Validate the value.
                        if value.is_empty() {
                            println!("Write error: INVALID_VALUE, For key: {}", key);
                            return Err(WriteError::InvalidValue);
                        }

                        println!("Wrote key: {}, value: {:?}", key, from_utf8(&value).unwrap());
                        entry.insert(StoreNode::Leaf(Some(value)));
                    }
                },
            }
            Ok(())
        }
    }
}

/// Creates a new instance of the server. Each server has its own bespoke, per-connection instance
/// of the key-value store.
async fn run_server(stream: StoreRequestStream) -> Result<(), Error> {
    // Create a new in-memory key-value store. The store will live for the lifetime of the
    // connection between the server and this particular client.
    let store = RefCell::new(HashMap::<String, StoreNode>::new());

    // Serve all requests on the protocol sequentially - a new request is not handled until its
    // predecessor has been processed.
    stream
        .map(|result| result.context("failed request"))
        .try_for_each(|request| async {
            // Match based on the method being invoked.
            match request {
                StoreRequest::WriteItem { attempt, responder } => {
                    println!("WriteItem request received");

                    // The `responder` parameter is a special struct that manages the outgoing reply
                    // to this method call. Calling `send` on the responder exactly once will send
                    // the reply.
                    responder
                        .send(write_item(&mut store.borrow_mut(), attempt, ""))
                        .context("error sending reply")?;
                    println!("WriteItem response sent");
                }
                StoreRequest::_UnknownMethod { ordinal, .. } => {
                    println!("Received an unknown method with ordinal {ordinal}");
                }
            }
            Ok(())
        })
        .await
}

// A helper enum that allows us to treat a `Store` service instance as a value.
enum IncomingService {
    Store(StoreRequestStream),
}

#[fuchsia::main]
async fn main() -> Result<(), Error> {
    println!("Started");

    // Add a discoverable instance of our `Store` protocol - this will allow the client to see the
    // server and connect to it.
    let mut fs = ServiceFs::new_local();
    fs.dir("svc").add_fidl_service(IncomingService::Store);
    fs.take_and_serve_directory_handle()?;
    println!("Listening for incoming connections");

    // The maximum number of concurrent clients that may be served by this process.
    const MAX_CONCURRENT: usize = 10;

    // Serve each connection simultaneously, up to the `MAX_CONCURRENT` limit.
    fs.for_each_concurrent(MAX_CONCURRENT, |IncomingService::Store(stream)| {
        run_server(stream).unwrap_or_else(|e| println!("{:?}", e))
    })
    .await;

    Ok(())
}
```

### C++ (Natural)

### Client

```c++
// TODO(https://fxbug.dev/42060656): C++ (Natural) implementation.
```

### Server

```c++
// TODO(https://fxbug.dev/42060656): C++ (Natural) implementation.
```

### C++ (Wire)

### Client

```c++
// TODO(https://fxbug.dev/42060656): C++ (Wire) implementation.
```

### Server

```c++
// TODO(https://fxbug.dev/42060656): C++ (Wire) implementation.
```


<br />

## fi-0157: Client/server end constraint must be a protocol

The first constraint applied to either `client_end` or `server_end` must point
to a `protocol` definition:

> [!WARNING]
> **Incorrect**

    library test.bad.fi0157;

    type MyStruct = struct {};
    alias ServerEnd = server_end:MyStruct;

Change the constraint to point to a protocol instead:

> [!TIP]
> **Correct**

    library test.good.fi0157;

    protocol MyProtocol {};
    alias ServerEnd = server_end:MyProtocol;

## fi-0158: Cannot bound twice

An `alias` declaration cannot change the value of an already set constraint on
the type it is aliasing:

> [!WARNING]
> **Incorrect**

    library test.bad.fi0158;

    alias ByteVec256 = vector<uint8>:256;
    alias ByteVec512 = ByteVec256:512;

Instead, the unbounded definition should receive its own `alias` declaration,
and each further constrained alias should inherit from it in turn:

> [!TIP]
> **Correct**

    library test.good.fi0158;

    alias AliasOfVectorOfString = vector<string>;
    alias AliasOfVectorOfStringSmall = AliasOfVectorOfString:8;
    alias AliasOfVectorOfStringLarge = AliasOfVectorOfString:16;

This is disallowed to avoid confusion and compiler implementation complexity.

## fi-0159: Struct cannot be optional

Structs cannot have the `optional` constraint:

> [!WARNING]
> **Incorrect**

    library test.bad.fi0159;

    type Date = struct {
        year uint16;
        month uint8;
        day uint8;
    };

    type Person = struct {
        name string;
        birthday Date:optional;
    };

Change `T:optional` to `box<T>` to fix the issue:

> [!TIP]
> **Correct**

    library test.good.fi0159;

    type Date = struct {
        year uint16;
        month uint8;
        day uint8;
    };

    type Person = struct {
        name string;
        birthday box<Date>;
    };

Only FIDL types that can be made optional with no change to the wire shape are
allowed to use the `optional` constraint. See the
[optionality](https://fuchsia.dev/docs/development/languages/fidl/examples/README#optionality) guide for more information.

## fi-0160: Type cannot be marked as optional twice

This error occurs when a type is made optional twice. Usually,
this occurs when the type is marked optional at both its use
and declaration sites.

> [!WARNING]
> **Incorrect**

    library test.bad.fi0160;

    alias MyAlias = vector<string>:optional;

    type MyStruct = struct {
        my_member MyAlias:optional;
    };

To fix this error, only make the type optional once.

For example, you can remove `:optional` from the use site.

> [!TIP]
> **Correct**

    library test.good.fi0160a;

    alias MyAlias = vector<string>:optional;

    type MyStruct = struct {
        my_member MyAlias;
    };

You could also remove `:optional` from the alias declaration.

    library test.good.fi0160b;

    alias MyAlias = vector<string>;

    type MyStruct = struct {
        my_member MyAlias:optional;
    };

## fi-0161: Must have non zero size

This error occurs when you try to set an array size constraint to 0. Arrays
cannot be zero-sized.

> [!WARNING]
> **Incorrect**

    library test.bad.fi0161;

    type Person = struct {
        name string;
        nicknames array<string, 0>;
    };

To fix this error, change the size constraint to a positive integer.

> [!TIP]
> **Correct**

    library test.good.fi0161;

    type Person = struct {
        name string;
        nicknames array<string, 5>;
    };

## fi-0162: Wrong number of layout parameters

Certain FIDL layouts, like `vector` and `array`, take parameters. This error
indicates that the highlighted type has an incorrect number of parameters
specified:

> [!WARNING]
> **Incorrect**

    library test.bad.fi0162a;

    type Foo = struct {
        bar array<8>;
    };

It can also appear in cases where a non-parameterizable type has erroneously had
parameters attached to it:

> [!WARNING]
> **Incorrect**

    library test.bad.fi0162b;

    type Foo = struct {
        bar uint8<8>;
    };

The fix is always to specify the correct number of parameters for the layout in
question:

> [!TIP]
> **Correct**

    library test.good.fi0162;

    type Foo = struct {
        bar array<uint8, 8>;
    };

The only parameterized types in FIDL are `array<T, N>`, `box<T>`, and
`vector<T>`. The `client_end` and `server_end` types used to be parameterized in
an [older](https://fuchsia.dev/docs/contribute/governance/rfcs/0050_syntax_revamp) version of the FIDL syntax, but this is no longer the case,
though it is a frequent source of run-ins with this error. These two types now
take their protocol specification as a (required) constraint instead.

Parameters, which are always listed inside of angle brackets `<...>`, have some
similarities to constraints, which appear after the `:...` character at the end
of the type. For example, at first blush, it may appear odd that `array<T, N>`
specifies its size as a parameter, while `vector<T>:N` specifies its size as a
constraint. The difference is that parameters always affect the wire layout
shape of the type in question, while constraints merely alter the set of values
that are considered acceptable at encode/decode time for that type, with no
effect on wire layout.

See [RFC-0050: FIDL Syntax Revamp](https://fuchsia.dev/docs/contribute/governance/rfcs/0050_syntax_revamp) for a more thorough discussion of
the distinction between the two concepts.

## fi-0163: Multiple constraint definitions

This error occurs when you try to define multiple constraint definitions using
more than one colon (`:`). Multiple constraint definitions must use
the angled bracket syntax `type:<constraint1, constraint2, etc>`.

> [!WARNING]
> **Incorrect**

    library test.bad.fi0163;

    type Person = struct {
      name string;
      favorite_color string:30:optional;
    };

To fix this error, use the angle bracket syntax for constraints:

> [!TIP]
> **Correct**

    library test.good.fi0163;

    type Person = struct {
        name string;
        favorite_color string:<30, optional>;
    };

## fi-0164: Too many constraints

This error occurs when you try to add more constraints to a type than are
supported. `string`, for example, supports at most two constraints.

> [!WARNING]
> **Incorrect**

    library test.bad.fi0164;

    type Person = struct {
        name string:<0, optional, 20>;
    };

To fix this issue, remove the extra constraints:

> [!TIP]
> **Correct**

    library test.good.fi0164;

    type Person = struct {
        name string:<20, optional>;
    };

## fi-0165: Expected type

This error occurs when you use a constant or protocol identifier when FIDL is
expecting a type.

> [!WARNING]
> **Incorrect**

    library test.bad.fi0165;

    type Person = struct {
        name string;
        nicknames vector<5>;
    };

To fix this error, update your code to use a valid type:

> [!TIP]
> **Correct**

    library test.good.fi0165;

    type Person = struct {
        name string;
        nicknames vector<string>:5;
    };

Protocols are not considered FIDL types and also cannot be used where a type is
expected.

## fi-0166: Unexpected constraint

This error occurs when you try to use a constraint where it's not expected.
Typically, this is due to a named `const` in the wrong position.

> [!WARNING]
> **Incorrect**

    library test.bad.fi0166;

    const MIN_SIZE uint8 = 1;
    const MAX_SIZE uint8 = 5;

    type Person = struct {
        name string;
        nicknames vector<string>:<MIN_SIZE, MAX_SIZE>;
    };

To fix this error, remove the constraint:

> [!TIP]
> **Correct**

    library test.good.fi0166;

    const MAX_SIZE uint8 = 5;

    type Person = struct {
        name string;
        nicknames vector<string>:<MAX_SIZE>;
    };

## fi-0167: Cannot constrain twice

Re-assigning the transport bound for a `client_end` or `server_end` that has
already had a transport bound defined through an `alias` declaration is
prohibited:

> [!WARNING]
> **Incorrect**

    library test.bad.fi0167;

    protocol MyOtherProtocol {};

    alias ClientEnd = client_end:MyProtocol;
    alias ServerEnd = server_end:MyProtocol;

    protocol MyProtocol {
        MyMethod(resource struct {
            my_client ClientEnd:MyOtherProtocol;
        }) -> (resource struct {
            my_server ServerEnd:MyOtherProtocol;
        });
    };

Instead, aliasing of `client_end` and `server_end` types should be avoided
entirely:

> [!TIP]
> **Correct**

    library test.good.fi0167;

    protocol MyProtocol {
        MyMethod(resource struct {
            my_client client_end:MyProtocol;
        }) -> (resource struct {
            my_server server_end:MyProtocol;
        });
    };

This is disallowed to avoid confusion and compiler implementation complexity.

## fi-0168: Client/server end must have protocol constraint

The first constraint applied to either `client_end` or `server_end` must point
to a `protocol` definition:

> [!WARNING]
> **Incorrect**

    library test.bad.fi0168;

    protocol MyProtocol {
        MyMethod(resource struct {
            server server_end;
        });
    };

Add a constraint pointing to the desired protocol:

> [!TIP]
> **Correct**

    library test.good.fi0168;

    protocol MyProtocol {
        MyMethod(resource struct {
            server server_end:MyProtocol;
        });
    };

## fi-0169: Boxed type cannot be optional

A type of the form `box<T>` cannot have the `optional` constraint applied to it:

> [!WARNING]
> **Incorrect**

    library test.bad.fi0169;

    type Color = struct {
        red byte;
        green byte;
        blue byte;
    };

    type MyStruct = struct {
        maybe_color box<Color>:optional;
    };

Boxed types are optional by definition, so adding the extra constraint is
unnecessary and redundant:

> [!TIP]
> **Correct**

    library test.good.fi0169;

    type Color = struct {
        red byte;
        green byte;
        blue byte;
    };

    type MyStruct = struct {
        maybe_color box<Color>;
    };

## fi-0170

> [!WARNING]
> **Deprecated:** This error code has been retired.

## fi-0171: Boxed type should use optional constraint instead

Only a type using the `struct` layout can be boxed; `union`, `vector`, `string`,
`client_end`, `server_end`, and `zx.Handle` must use the `optional` constraint
instead:

> [!WARNING]
> **Incorrect**

    library test.bad.fi0171;

    using zx;

    type MyStruct = resource struct {
        my_resource_member box<zx.Handle>;
    };

Convert `box<T>` to `T:optional` to fix this issue:

> [!TIP]
> **Correct**

    library test.good.fi0171;

    using zx;

    type MyStruct = resource struct {
        my_resource_member zx.Handle:optional;
    };

Only FIDL types that can be made optional with no change to the wire shape are
allowed to use the `optional` constraint. See the
[optionality](https://fuchsia.dev/docs/development/languages/fidl/examples/README#optionality) guide, or the expandable below, for more
information.

#### FIDL recipe: Optionality

Certain FIDL types can be made *optional* with no change to the wire shape of
their containing message with the addition of the `:optional` constraint.
Further, the `table` layout is always optional, while the `struct` layout never
is. To make a `struct` optional, it must be wrapped in a `box<T>`, thereby
changing the wire shape of its containing message.

| Base type | Optional version | Does optionality change the wire layout? |
|---|---|---|
| `struct {...}` | `box<struct {...}>` | Yes |
| `table {...}` | `table {...}` | No |
| `union {...}` | `union {...}:optional` | No |
| `vector<T>` | `vector<T>:optional` | No |
| `string` | `string:optional` | No |
| `zx.Handle` | `zx.Handle:optional` | No |
| `client_end:P` | `client_end:<P, optional>` | No |
| `server_end:P` | `server_end:<P, optional>` | No |

All other types (`bits`, `enum`, `array<T, N>`, and the primitive types) cannot
be made optional.

> [!CAUTION]
> **Caution:** This example implementation builds on the [key-value store baseline
> example](https://fuchsia.dev/docs/development/languages/fidl/examples/key_value_store#baseline) as a prerequisite. You can see more information about setting up the extended base case in this document.

In this variant, we allow our key-value store to take other key-value stores as
members. In short, we turn it into a tree. We do this by replacing the original
definition of `value` with one that utilizes a two-member `union`: one variant
stores leaf nodes using the same `vector<byte>` type as before, while the other
stores branch nodes in the form of other nested stores.

### Reasoning

Here, we see several uses of *optionality*, whereby we can declare a type that
may or may not exist. There are three flavors of optionality in FIDL:

- Types that have are always stored [out-of-line](https://fuchsia.dev/docs/reference/fidl/language/wire-format#primary_and_secondary_objects) on the wire, and thus have a builtin way to describe "absentness" via the [null envelope](https://fuchsia.dev/docs/reference/fidl/language/wire-format#envelopes). Enabling optionality for these types doesn't affect the wire shape of messages they are included in - it simply changes which values are valid for that particular type. The `union`, `vector<T>`, `client_end`, `server_end`, and `zx.Handle` types can all be made optional via the addition of the `:optional` constraint. By making our `value` `union` optional, we are able to introduce a canonical "null" entry, in the form of an absent `value`. This means that empty `bytes` and absent/empty `store` properties are invalid values.
- Unlike the aforementioned types, the `struct` layout has no extra space where a null header can be stored. Because of this, it needs to be wrapped in an envelope, changing the on-the-wire shape of the message it is being included in. To ensure that this wire-modifying effect easily legible, the `Item` `struct` type must be wrapped in a `box<T>` type template.
- Finally, `table` layouts are always optional. An absent `table` is simply one with none of its members set.

Trees are a naturally self-referential data structure: any node in the tree may
contain a leaf with pure data (in this case, a string), or a sub-tree with more
nodes. This requires recursion: the definition of `Item` is now transitively
dependent on itself! Representing *recursive types* in FIDL can be a bit tricky,
especially because support is currently [somewhat
limited](https://fxbug.dev/42110612). We can support such types as long as there is
at least one optional type in the cycle created by the self-reference. For
instance, here we define the `items` `struct` member to be a `box<Item>`,
thereby breaking the includes cycle.

These changes also make heavy use of *anonymous types* , or types whose
declarations are inlined at their sole point of use, rather than being named,
top-level `type` declarations of their own. By default, the names of anonymous
types in the generated language bindings are taken from their local context. For
instance, the newly introduced `flexible union` takes on its owning member's
name `Value`, the newly introduced `struct` would become `Store`, and so on.
Because this heuristic can sometimes cause collisions, FIDL provides an escape
hatch by allowing the author to manually override an anonymous type's *generated
name* . This is done via the `@generated_name` attribute, which allows one to
change the name generated by backends. We can use one here, where the would-be
`Store` type is renamed to `NestedStore` to prevent a name collision with the
`protocol` declaration that uses that same name.

### Implementation

> [!NOTE]
> **Note:** The source code for this example is located at [//examples/fidl/new/key_value_store/support_trees](https://cs.opensource.google/fuchsia/fuchsia/+/main:/examples/fidl/new/key_value_store/support_trees). This directory includes tests exercising the implementation in all supported languages, which may be run locally by executing the following from the command line: `fx set core.x64 --with=//examples/fidl/new:tests && fx test
> keyvaluestore_supporttrees`.

The FIDL, CML, and realm interface definitions are modified as follows:

### FIDL

```
// Copyright 2022 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
library examples.keyvaluestore.supporttrees;

/// An item in the store. The key must match the regex `^[A-z][A-z0-9_\.\/]{2,62}[A-z0-9]$`. That
/// is, it must start with a letter, end with a letter or number, contain only letters, numbers,
/// periods, and slashes, and be between 4 and 64 characters long.
type Item = struct {
    key string:128;
    value strict union {
        // Keep the original `bytes` as one of the options in the new union. All leaf nodes in the
        // tree must be `bytes`, or absent unions (representing empty). Empty byte arrays are
        // disallowed.
        1: bytes vector<byte>:64000;

        // Allows a store within a store, thereby turning our flat key-value store into a tree
        // thereof. Note the use of `@generated_name` to prevent a type-name collision with the
        // `Store` protocol below, and the use of `box<T>` to ensure that there is a break in the
        // chain of recursion, thereby allowing `Item` to include itself in its own definition.
        //
        // This is a table so that added fields, like for example a `hash`, can be easily added in
        // the future.
        2: store @generated_name("nested_store") table {
            1: items vector<box<Item>>;
        };
    }:optional;
};

/// An enumeration of things that may go wrong when trying to write a value to our store.
type WriteError = flexible enum {
    UNKNOWN = 0;
    INVALID_KEY = 1;
    INVALID_VALUE = 2;
    ALREADY_EXISTS = 3;
};

/// A very basic key-value store.
@discoverable
open protocol Store {
    /// Writes an item to the store.
    flexible WriteItem(struct {
        attempt Item;
    }) -> () error WriteError;
};
```

### CML

### Client

```
// Copyright 2022 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
{
    include: [ "syslog/client.shard.cml" ],
    program: {
        runner: "elf",
        binary: "bin/client_bin",
    },
    use: [
        { protocol: "examples.keyvaluestore.supporttrees.Store" },
        {
            config: "fuchsia.examples.keyvaluestore.supporttrees.WriteItems",
            key: "write_items",
            type: "vector",
            max_count: 16,
            element: {
                type: "string",
                max_size: 64,
            },
            availability: "transitional",
            default: [],
        },

        // A newline separated list nested entries. The first line should be the key
        // for the nested store, and each subsequent entry should be a pointer to a text file
        // containing the string value. The name of that text file (without the `.txt` suffix) will
        // serve as the entries key.
        {
            config: "fuchsia.examples.keyvaluestore.supporttrees.WriteNested",
            key: "write_nested",
            type: "vector",
            max_count: 16,
            element: {
                type: "string",
                max_size: 64,
            },
            availability: "transitional",
            default: [],
        },

        // A list of keys, all of which will be populated as null entries.
        {
            config: "fuchsia.examples.keyvaluestore.supporttrees.WriteNull",
            key: "write_null",
            type: "vector",
            max_count: 16,
            element: {
                type: "string",
                max_size: 64,
            },
            availability: "transitional",
            default: [],
        },

    ],
}
```

### Server

```
// Copyright 2022 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
{
    include: [ "syslog/client.shard.cml" ],
    program: {
        runner: "elf",
        binary: "bin/server_bin",
    },
    capabilities: [
        { protocol: "examples.keyvaluestore.supporttrees.Store" },
    ],
    expose: [
        {
            protocol: "examples.keyvaluestore.supporttrees.Store",
            from: "self",
        },
    ],
}
```

### Realm

```
// Copyright 2022 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
{
    children: [
        {
            name: "client",
            url: "#meta/client.cm",
        },
        {
            name: "server",
            url: "#meta/server.cm",
        },
    ],
    offer: [
        // Route the protocol under test from the server to the client.
        {
            protocol: "examples.keyvaluestore.supporttrees.Store",
            from: "#server",
            to: "#client",
        },

        // Route diagnostics support to all children.
        {
            dictionary: "diagnostics",
            from: "parent",
            to: [
                "#client",
                "#server",
            ],
        },
    ],
}
```

Client and server implementations can then be written in any supported language:

### Rust

### Client

```rust
// Copyright 2022 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

use {
    anyhow::{Context as _, Error},
    config::Config,
    fidl_examples_keyvaluestore_supporttrees::{Item, NestedStore, StoreMarker, Value},
    fuchsia_component::client::connect_to_protocol,
    std::{thread, time},
};

#[fuchsia::main]
async fn main() -> Result<(), Error> {
    println!("Started");

    // Load the structured config values passed to this component at startup.
    let config = Config::take_from_startup_handle();

    // Use the Component Framework runtime to connect to the newly spun up server component. We wrap
    // our retained client end in a proxy object that lets us asynchronously send `Store` requests
    // across the channel.
    let store = connect_to_protocol::<StoreMarker>()?;
    println!("Outgoing connection enabled");

    // This client's structured config has one parameter, a vector of strings. Each string is the
    // path to a resource file whose filename is a key and whose contents are a value. We iterate
    // over them and try to write each key-value pair to the remote store.
    for key in config.write_items.into_iter() {
        let path = format!("/pkg/data/{}.txt", key);
        let value = std::fs::read_to_string(path.clone())
            .with_context(|| format!("Failed to load {path}"))?;
        let res = store
            .write_item(&Item {
                key: key.clone(),
                value: Some(Box::new(Value::Bytes(value.into_bytes()))),
            })
            .await;
        match res? {
            Ok(_) => println!("WriteItem Success at key: {}", key),
            Err(err) => println!("WriteItem Error: {}", err.into_primitive()),
        }
    }

    // Add nested entries to the key-value store as well. The entries are strings, where the first
    // line is the key of the entry, and each subsequent entry should be a pointer to a text file
    // containing the string value. The name of that text file (without the `.txt` suffix) will
    // serve as the entries key.
    for spec in config.write_nested.into_iter() {
        let mut items = vec![];
        let mut nested_store = NestedStore::default();
        let mut lines = spec.split("\n");
        let key = lines.next().unwrap();

        // For each entry, make a new entry in the `NestedStore` being built.
        for entry in lines {
            let path = format!("/pkg/data/{}.txt", entry);
            let contents = std::fs::read_to_string(path.clone())
                .with_context(|| format!("Failed to load {path}"))?;
            items.push(Some(Box::new(Item {
                key: entry.to_string(),
                value: Some(Box::new(Value::Bytes(contents.into()))),
            })));
        }
        nested_store.items = Some(items);

        // Send the `NestedStore`, represented as a vector of values.
        let res = store
            .write_item(&Item {
                key: key.to_string(),
                value: Some(Box::new(Value::Store(nested_store))),
            })
            .await;
        match res? {
            Ok(_) => println!("WriteItem Success at key: {}", key),
            Err(err) => println!("WriteItem Error: {}", err.into_primitive()),
        }
    }

    // Each entry in this list is a null value in the store.
    for key in config.write_null.into_iter() {
        match store.write_item(&Item { key: key.to_string(), value: None }).await? {
            Ok(_) => println!("WriteItem Success at key: {}", key),
            Err(err) => println!("WriteItem Error: {}", err.into_primitive()),
        }
    }

    // TODO(https://fxbug.dev/42156498): We need to sleep here to make sure all logs get drained. Once the
    // referenced bug has been resolved, we can remove the sleep.
    thread::sleep(time::Duration::from_secs(2));
    Ok(())
}
```

### Server

```rust
// Copyright 2022 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

// Note: For the clarity of this example, allow code to be unused.
#![allow(dead_code)]

use {
    anyhow::{Context as _, Error},
    fidl_examples_keyvaluestore_supporttrees::{
        Item, StoreRequest, StoreRequestStream, Value, WriteError,
    },
    fuchsia_component::server::ServiceFs,
    futures::prelude::*,
    regex::Regex,
    std::cell::RefCell,
    std::collections::HashMap,
    std::collections::hash_map::Entry,
    std::str::from_utf8,
    std::sync::LazyLock,
};

static KEY_VALIDATION_REGEX: LazyLock<Regex> = LazyLock::new(|| {
    Regex::new(r"^[A-Za-z]\w+[A-Za-z0-9]$").expect("Key validation regex failed to compile")
});

// A representation of a key-value store that can contain an arbitrarily deep nesting of other
// key-value stores.
#[allow(clippy::box_collection, reason = "mass allow for https://fxbug.dev/381896734")]
enum StoreNode {
    Leaf(Option<Vec<u8>>),
    Branch(Box<HashMap<String, StoreNode>>),
}

/// Recursive item writer, which takes a `StoreNode` that may not necessarily be the root node, and
/// writes an entry to it.
fn write_item(
    store: &mut HashMap<String, StoreNode>,
    attempt: Item,
    path: &str,
) -> Result<(), WriteError> {
    // Validate the key.
    if !KEY_VALIDATION_REGEX.is_match(attempt.key.as_str()) {
        println!("Write error: INVALID_KEY, For key: {}", attempt.key);
        return Err(WriteError::InvalidKey);
    }

    // Write to the store, validating that the key did not already exist.
    match store.entry(attempt.key) {
        Entry::Occupied(entry) => {
            println!("Write error: ALREADY_EXISTS, For key: {}", entry.key());
            Err(WriteError::AlreadyExists)
        }
        Entry::Vacant(entry) => {
            let key = format!("{}{}", path, entry.key());
            match attempt.value {
                // Null entries are allowed.
                None => {
                    println!("Wrote value: NONE at key: {}", key);
                    entry.insert(StoreNode::Leaf(None));
                }
                Some(value) => match *value {
                    // If this is a nested store, recursively make a new store to insert at this
                    // position.
                    Value::Store(entry_list) => {
                        // Validate the value - absent stores, items lists with no children, or any
                        // of the elements within that list being empty boxes, are all not allowed.
                        if entry_list.items.is_some() {
                            let items = entry_list.items.unwrap();
                            if !items.is_empty() && items.iter().all(|i| i.is_some()) {
                                let nested_path = format!("{}/", key);
                                let mut nested_store = HashMap::<String, StoreNode>::new();
                                for item in items.into_iter() {
                                    write_item(&mut nested_store, *item.unwrap(), &nested_path)?;
                                }

                                println!("Created branch at key: {}", key);
                                entry.insert(StoreNode::Branch(Box::new(nested_store)));
                                return Ok(());
                            }
                        }

                        println!("Write error: INVALID_VALUE, For key: {}", key);
                        return Err(WriteError::InvalidValue);
                    }

                    // This is a simple leaf node on this branch.
                    Value::Bytes(value) => {
                        // Validate the value.
                        if value.is_empty() {
                            println!("Write error: INVALID_VALUE, For key: {}", key);
                            return Err(WriteError::InvalidValue);
                        }

                        println!("Wrote key: {}, value: {:?}", key, from_utf8(&value).unwrap());
                        entry.insert(StoreNode::Leaf(Some(value)));
                    }
                },
            }
            Ok(())
        }
    }
}

/// Creates a new instance of the server. Each server has its own bespoke, per-connection instance
/// of the key-value store.
async fn run_server(stream: StoreRequestStream) -> Result<(), Error> {
    // Create a new in-memory key-value store. The store will live for the lifetime of the
    // connection between the server and this particular client.
    let store = RefCell::new(HashMap::<String, StoreNode>::new());

    // Serve all requests on the protocol sequentially - a new request is not handled until its
    // predecessor has been processed.
    stream
        .map(|result| result.context("failed request"))
        .try_for_each(|request| async {
            // Match based on the method being invoked.
            match request {
                StoreRequest::WriteItem { attempt, responder } => {
                    println!("WriteItem request received");

                    // The `responder` parameter is a special struct that manages the outgoing reply
                    // to this method call. Calling `send` on the responder exactly once will send
                    // the reply.
                    responder
                        .send(write_item(&mut store.borrow_mut(), attempt, ""))
                        .context("error sending reply")?;
                    println!("WriteItem response sent");
                }
                StoreRequest::_UnknownMethod { ordinal, .. } => {
                    println!("Received an unknown method with ordinal {ordinal}");
                }
            }
            Ok(())
        })
        .await
}

// A helper enum that allows us to treat a `Store` service instance as a value.
enum IncomingService {
    Store(StoreRequestStream),
}

#[fuchsia::main]
async fn main() -> Result<(), Error> {
    println!("Started");

    // Add a discoverable instance of our `Store` protocol - this will allow the client to see the
    // server and connect to it.
    let mut fs = ServiceFs::new_local();
    fs.dir("svc").add_fidl_service(IncomingService::Store);
    fs.take_and_serve_directory_handle()?;
    println!("Listening for incoming connections");

    // The maximum number of concurrent clients that may be served by this process.
    const MAX_CONCURRENT: usize = 10;

    // Serve each connection simultaneously, up to the `MAX_CONCURRENT` limit.
    fs.for_each_concurrent(MAX_CONCURRENT, |IncomingService::Store(stream)| {
        run_server(stream).unwrap_or_else(|e| println!("{:?}", e))
    })
    .await;

    Ok(())
}
```

### C++ (Natural)

### Client

```c++
// TODO(https://fxbug.dev/42060656): C++ (Natural) implementation.
```

### Server

```c++
// TODO(https://fxbug.dev/42060656): C++ (Natural) implementation.
```

### C++ (Wire)

### Client

```c++
// TODO(https://fxbug.dev/42060656): C++ (Wire) implementation.
```

### Server

```c++
// TODO(https://fxbug.dev/42060656): C++ (Wire) implementation.
```


<br />

## fi-0172: Resource definition must use uint32 subtype

The subtype of a `resource_definition` declaration must be `uint32`:

> [!WARNING]
> **Incorrect**

    library test.bad.fi0172;

    type MySubtype = strict enum : uint32 {
        NONE = 0;
    };

    resource_definition MyResource : uint8 {
        properties {
            subtype MySubtype;
        };
    };

Change the subtype to an `uint32` to fix this error:

> [!TIP]
> **Correct**

    library test.good.fi0172;

    type MySubtype = strict enum : uint32 {
        NONE = 0;
    };

    resource_definition MyResource : uint32 {
        properties {
            subtype MySubtype;
        };
    };

This is an error related to FIDL's internal implementation, and thus should only
ever be surfaced to developers working on FIDL's core libraries. End users
should never see this error.

The `resource_definition` declaration it refers to is FIDL's internal means of
defining resources like handles, and is likely to change in the future as part
of the [handle generalization](https://fxbug.dev/42143256) effort.

## fi-0173: Resource definition must specify subtype

The `resource_definition` declaration cannot omit the `subtype` member:

> [!WARNING]
> **Incorrect**

    library test.bad.fi0173;

    resource_definition MyResource : uint32 {
        properties {
            rights uint32;
        };
    };

Point this member to a valid `enum : uint32` declaration:

> [!TIP]
> **Correct**

    library test.good.fi0173;

    resource_definition MyResource : uint32 {
        properties {
            subtype flexible enum : uint32 {};
            rights uint32;
        };
    };

This is an error related to FIDL's internal implementation, and thus should only
ever be surfaced to developers working on FIDL's core libraries. End users
should never see this error.

The `resource_definition` declaration it refers to is FIDL's internal means of
defining resources like handles, and is likely to change in the future as part
of the [handle generalization](https://fxbug.dev/42143256) effort.

## fi-0174

> [!WARNING]
> **Deprecated:** This error code has been retired.

## fi-0175: Resource definition subtype property must refer to enum

The `resource_definition` declaration cannot use a non-`enum` as the `subtype`
member:

> [!WARNING]
> **Incorrect**

    library test.bad.fi0175;

    resource_definition MyResource : uint32 {
        properties {
            subtype struct {};
        };
    };

Point this member to a valid `enum : uint32` declaration:

> [!TIP]
> **Correct**

    library test.good.fi0175;

    resource_definition MyResource : uint32 {
        properties {
            subtype flexible enum : uint32 {};
        };
    };

This is an error related to FIDL's internal implementation, and thus should only
ever be surfaced to developers working on FIDL's core libraries. End users
should never see this error.

The `resource_definition` declaration it refers to is FIDL's internal means of
defining resources like handles, and is likely to change in the future as part
of the [handle generalization](https://fxbug.dev/42143256) effort.

## fi-0176

> [!WARNING]
> **Deprecated:** This error code has been retired.

## fi-0177: Resource definition rights property must refer to bits

The `resource_definition` declaration cannot use a non-`bits` as the `rights`
member:

> [!WARNING]
> **Incorrect**

    library test.bad.fi0177;

    type MySubtype = enum : uint32 {
        NONE = 0;
        VMO = 3;
    };

    resource_definition MyResource : uint32 {
        properties {
            subtype MySubtype;
            rights string;
        };
    };

Point this member to a valid `bits : uint32` declaration:

> [!TIP]
> **Correct**

    library test.good.fi0177;

    type MySubtype = enum : uint32 {
        NONE = 0;
        VMO = 3;
    };

    resource_definition MyResource : uint32 {
        properties {
            subtype MySubtype;
            rights uint32;
        };
    };

This is an error related to FIDL's internal implementation, and thus should only
ever be surfaced to developers working on FIDL's core libraries. End users
should never see this error.

The `resource_definition` declaration it refers to is FIDL's internal means of
defining resources like handles, and is likely to change in the future as part
of the [handle generalization](https://fxbug.dev/42143256) effort.

## fi-0178: Unused import

Not referencing a dependency imported via the `using` declaration is an error:

> [!WARNING]
> **Incorrect**

    library test.bad.fi0178;

    using dependent;

    type Foo = struct {
        does_not int64;
        use_dependent int32;
    };

Make sure all such imports are used in the library importing, either by actually
referencing the import, or removing the unused dependency:

> [!TIP]
> **Correct**

    library test.good.fi0178;

    using dependent;

    type Foo = struct {
        dep dependent.Bar;
    };

## fi-0179: Newtypes cannot be constrained

> [!WARNING]
> **Experimental:** Newtypes are an unstable feature gated behind the `--experimental allow_new_types` fidlc flag.

Newtypes from [RFC-0052: Type aliasing and new types](https://fuchsia.dev/docs/contribute/governance/rfcs/0052_type_aliasing_named_types) are not
allowed to be constrained. For example, a newtype of `string` cannot be
constrained with `:optional`:

> [!WARNING]
> **Incorrect**

    library test.bad.fi0179;

    type Name = string;

    type Info = struct {
        name Name:optional;
    };

In this situation, we can make make the `name` field optional by putting it in a
table rather than a struct:

> [!TIP]
> **Correct**

    library test.good.fi0179;

    type Name = string;

    type Info = table {
        1: name Name;
    };

This restriction simplifies the design of newtypes. It's not clear what the API
and ABI should look like for a constrained newtype in general (e.g., should the
constraints apply to the newtype itself, or flow through to the underlying
type?).

## fi-0180: Zircon C types are experimental

> [!WARNING]
> **Experimental:** Zircon C types are an unstable feature gated behind the `--experimental zx_c_types` fidlc flag.

The built-in types `usize`, `uintptr`, `uchar`, and `experimental_pointer` are
being developed for the [Zither](https://cs.opensource.google/fuchsia/fuchsia/+/main:/zircon/tools/zither/README.md) project. They cannot be used in ordinary FIDL
libraries:

> [!WARNING]
> **Incorrect**

    library test.bad.fi0180;

    type Data = struct {
        size usize64;
    };

Instead, use a different type, for example `uint64` instead of `usize`:

> [!TIP]
> **Correct**

    library test.good.fi0180;

    type Data = struct {
        size uint64;
    };

## fi-0181: Library attribute argument references constant

Attribute arguments on library declarations are not allowed to reference
constants:

> [!WARNING]
> **Incorrect**

    @custom_attribute(VALUE)
    library test.bad.fi0181a;

    const VALUE string = "hello";

Instead, provide a literal argument:

> [!TIP]
> **Correct**

    @custom_attribute("hello")
    library test.good.fi0181a;

This restriction exists because it is rarely needed and supporting it adds
unwarranted complexity to the compiler.

## fi-0182

> [!WARNING]
> **Deprecated:** This error code has been retired.

## fi-0183

> [!WARNING]
> **Deprecated:** This error code has been retired.

## fi-0184: Unexpected control character

String literals are not allowed to contain raw control characters (ASCII
characters from `0x00` to `0x1f`):

> [!WARNING]
> **Incorrect**

    library test.bad.fi0184;

    const TAB string = "	"; // literal tab character

Instead, use an escape sequence. In this case, `\t` is the right one:

> [!TIP]
> **Correct**

    library test.good.fi0184a;

    const TAB string = "\t";

Alternatively, you can use a Unicode escape sequence. This works for any Unicode
code point:

> [!TIP]
> **Correct**

    library test.good.fi0184b;

    const TAB string = "\u{9}";

Raw control characters are not allowed in string literals because they are all
either whitespace or non-printable, so they would be confusing and hard to
notice if embedded directly in the FIDL source file.

## fi-0185: Unicode escape sequence missing braces

Unicode escape sequences in string literals must specify a code point in braces:

> [!WARNING]
> **Incorrect**

    library test.bad.fi0185;

    const SMILE string = "\u";

To fix the error, specify a code point in braces:

> [!TIP]
> **Correct**

    library test.good.fi0185;

    const SMILE string = "\u{1F600}";

## fi-0186: Unterminated Unicode escape sequence

Unicode escape sequences in string literals must be terminated:

> [!WARNING]
> **Incorrect**

    library test.bad.fi0186;

    const SMILE string = "\u{1F600";

To terminate the escape sequence, add a closing brace `}`:

> [!TIP]
> **Correct**

    library test.good.fi0186;

    const SMILE string = "\u{1F600}";

## fi-0187: Empty Unicode escape sequence

Unicode escape sequences in string literals must have at least one hex digit:

> [!WARNING]
> **Incorrect**

    library test.bad.fi0187;

    const SMILE string = "\u{}";

To fix the error, add hex digits to specify a Unicode code point:

> [!TIP]
> **Correct**

    library test.good.fi0187;

    const SMILE string = "\u{1F600}";

## fi-0188: Too many digits in Unicode escape sequence

Unicode escape sequences in string literals cannot have more than 6 hex digits:

> [!WARNING]
> **Incorrect**

    library test.bad.fi0188;

    const SMILE string = "\u{001F600}";

To fix the error, specify at most 6 hex digits. In this case, there are leading
zeros that we can remove:

> [!TIP]
> **Correct**

    library test.good.fi0188;

    const SMILE string = "\u{1F600}";

This restriction exists because all valid Unicode code points fit in 6 hex
digits, so there is no reason to allow more digits than that.

## fi-0189: Unicode code point too large

Unicode escape sequences in string literals cannot specify a Unicode code point
greater than the maximum of `0x10ffff`:

> [!WARNING]
> **Incorrect**

    library test.bad.fi0189;

    const TOO_LARGE string = "\u{110000}";

Instead, make sure the code point is valid:

> [!TIP]
> **Correct**

    library test.good.fi0189;

    const MAX_CODEPOINT string = "\u{10ffff}";

## fi-0190

> [!WARNING]
> **Deprecated:** This error code has been retired.

## fi-0191: Method must specify strictness

This error indicates that a FIDL method does not have a `strict` or `flexible`
modifier.

> [!WARNING]
> **Incorrect**

    library test.bad.fi0191;

    open protocol Example {
        OneWay();
    };

To fix this, add either `strict` or `flexible` to the method. If this is an
existing method, you must use `strict` and should see the [compatibility
guide](https://fuchsia.dev/docs/development/languages/fidl/guides/compatibility/README#strict-flexible) for guidance on changing it to `flexible`. If
this is a new method, you should see the [API rubric](https://fuchsia.dev/docs/development/api/fidl#strict-flexible-method) for
guidance on which to choose.

> [!TIP]
> **Correct**

    library test.good.fi0191;

    open protocol Example {
        flexible OneWay();
    };

FIDL is currently undergoing a migration in order to support handling unknown
interactions, defined in [RFC-0138](https://fuchsia.dev/docs/contribute/governance/rfcs/0138_handling_unknown_interactions). This new feature allows the
modifiers `strict` and `flexible` to apply to FIDL methods and events.
Historically, all methods behaved as though they were `strict`, however at the
end of this migration, the default value will be `flexible`. To avoid confusion
and possible issues arising from changing the method default modifier from
`strict` to `flexible`, the method modifier is required during this transitional
period. When the migration is complete, this will be changed from an error to a
linter suggestion.

For more information about unknown interactions, see the [FIDL language
reference](https://fuchsia.dev/docs/reference/fidl/language/language#unknown-interactions).

## fi-0192: Protocol must specify openness

This error indicates that a FIDL protocol does not have an `open`, `ajar`, or
`closed` modifier.

> [!WARNING]
> **Incorrect**

    library test.bad.fi0192;

    protocol ImplicitOpenness {};

To fix this, add `open`, `ajar`, or `closed` to the protocol. If this is an
existing protocol, you must use `closed` and should see the [compatibility
guide](https://fuchsia.dev/docs/development/languages/fidl/guides/compatibility/README#open-ajar-closed) for guidance on changing it to `open` or
`ajar`. If this is a new method, you should see the [API
rubric](https://fuchsia.dev/docs/development/api/fidl#open-ajar-closed) for guidance on which to choose.

> [!TIP]
> **Correct**

    library test.good.fi0192;

    open protocol ImplicitOpenness {};

FIDL is currently undergoing a migration in order to support handling unknown
interactions, defined in [RFC-0138](https://fuchsia.dev/docs/contribute/governance/rfcs/0138_handling_unknown_interactions). This new feature adds three
new modifiers, `open`, `ajar`, and `closed`, which apply to FIDL protocols.
Historically, all protocols behaved as though they were `closed`, however at the
end of this migration, the default value will be `open`. To avoid confusion and
possible issues arising from changing the protocol default modifier from
`closed` to `open`, the protocol modifier is required during this transitional
period. When the migration is complete, this will be changed from an error to a
linter suggestion.

For more information about unknown interactions, see the [FIDL language
reference](https://fuchsia.dev/docs/reference/fidl/language/language#unknown-interactions).

## fi-0193: Cannot box type

Types other than structs cannot be boxed. For example, a primitive type cannot be boxed:

> [!WARNING]
> **Incorrect**

    library test.bad.fi0193;

    type MyStruct = struct {
        my_member box<bool>;
    };

To box a primitive, put it in a single-member `struct` instead:

> [!TIP]
> **Correct**

    library test.good.fi0193;

    type MyStruct = struct {
        my_member box<struct {
            my_bool bool;
        }>;
    };

Note that some types can be made optional via the use of the `optional`
constraint. See the [optionality](https://fuchsia.dev/docs/development/languages/fidl/examples/README#optionality) guide, or the expandable
below, for more information.

#### FIDL recipe: Optionality

Certain FIDL types can be made *optional* with no change to the wire shape of
their containing message with the addition of the `:optional` constraint.
Further, the `table` layout is always optional, while the `struct` layout never
is. To make a `struct` optional, it must be wrapped in a `box<T>`, thereby
changing the wire shape of its containing message.

| Base type | Optional version | Does optionality change the wire layout? |
|---|---|---|
| `struct {...}` | `box<struct {...}>` | Yes |
| `table {...}` | `table {...}` | No |
| `union {...}` | `union {...}:optional` | No |
| `vector<T>` | `vector<T>:optional` | No |
| `string` | `string:optional` | No |
| `zx.Handle` | `zx.Handle:optional` | No |
| `client_end:P` | `client_end:<P, optional>` | No |
| `server_end:P` | `server_end:<P, optional>` | No |

All other types (`bits`, `enum`, `array<T, N>`, and the primitive types) cannot
be made optional.

> [!CAUTION]
> **Caution:** This example implementation builds on the [key-value store baseline
> example](https://fuchsia.dev/docs/development/languages/fidl/examples/key_value_store#baseline) as a prerequisite. You can see more information about setting up the extended base case in this document.

In this variant, we allow our key-value store to take other key-value stores as
members. In short, we turn it into a tree. We do this by replacing the original
definition of `value` with one that utilizes a two-member `union`: one variant
stores leaf nodes using the same `vector<byte>` type as before, while the other
stores branch nodes in the form of other nested stores.

### Reasoning

Here, we see several uses of *optionality*, whereby we can declare a type that
may or may not exist. There are three flavors of optionality in FIDL:

- Types that have are always stored [out-of-line](https://fuchsia.dev/docs/reference/fidl/language/wire-format#primary_and_secondary_objects) on the wire, and thus have a builtin way to describe "absentness" via the [null envelope](https://fuchsia.dev/docs/reference/fidl/language/wire-format#envelopes). Enabling optionality for these types doesn't affect the wire shape of messages they are included in - it simply changes which values are valid for that particular type. The `union`, `vector<T>`, `client_end`, `server_end`, and `zx.Handle` types can all be made optional via the addition of the `:optional` constraint. By making our `value` `union` optional, we are able to introduce a canonical "null" entry, in the form of an absent `value`. This means that empty `bytes` and absent/empty `store` properties are invalid values.
- Unlike the aforementioned types, the `struct` layout has no extra space where a null header can be stored. Because of this, it needs to be wrapped in an envelope, changing the on-the-wire shape of the message it is being included in. To ensure that this wire-modifying effect easily legible, the `Item` `struct` type must be wrapped in a `box<T>` type template.
- Finally, `table` layouts are always optional. An absent `table` is simply one with none of its members set.

Trees are a naturally self-referential data structure: any node in the tree may
contain a leaf with pure data (in this case, a string), or a sub-tree with more
nodes. This requires recursion: the definition of `Item` is now transitively
dependent on itself! Representing *recursive types* in FIDL can be a bit tricky,
especially because support is currently [somewhat
limited](https://fxbug.dev/42110612). We can support such types as long as there is
at least one optional type in the cycle created by the self-reference. For
instance, here we define the `items` `struct` member to be a `box<Item>`,
thereby breaking the includes cycle.

These changes also make heavy use of *anonymous types* , or types whose
declarations are inlined at their sole point of use, rather than being named,
top-level `type` declarations of their own. By default, the names of anonymous
types in the generated language bindings are taken from their local context. For
instance, the newly introduced `flexible union` takes on its owning member's
name `Value`, the newly introduced `struct` would become `Store`, and so on.
Because this heuristic can sometimes cause collisions, FIDL provides an escape
hatch by allowing the author to manually override an anonymous type's *generated
name* . This is done via the `@generated_name` attribute, which allows one to
change the name generated by backends. We can use one here, where the would-be
`Store` type is renamed to `NestedStore` to prevent a name collision with the
`protocol` declaration that uses that same name.

### Implementation

> [!NOTE]
> **Note:** The source code for this example is located at [//examples/fidl/new/key_value_store/support_trees](https://cs.opensource.google/fuchsia/fuchsia/+/main:/examples/fidl/new/key_value_store/support_trees). This directory includes tests exercising the implementation in all supported languages, which may be run locally by executing the following from the command line: `fx set core.x64 --with=//examples/fidl/new:tests && fx test
> keyvaluestore_supporttrees`.

The FIDL, CML, and realm interface definitions are modified as follows:

### FIDL

```
// Copyright 2022 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
library examples.keyvaluestore.supporttrees;

/// An item in the store. The key must match the regex `^[A-z][A-z0-9_\.\/]{2,62}[A-z0-9]$`. That
/// is, it must start with a letter, end with a letter or number, contain only letters, numbers,
/// periods, and slashes, and be between 4 and 64 characters long.
type Item = struct {
    key string:128;
    value strict union {
        // Keep the original `bytes` as one of the options in the new union. All leaf nodes in the
        // tree must be `bytes`, or absent unions (representing empty). Empty byte arrays are
        // disallowed.
        1: bytes vector<byte>:64000;

        // Allows a store within a store, thereby turning our flat key-value store into a tree
        // thereof. Note the use of `@generated_name` to prevent a type-name collision with the
        // `Store` protocol below, and the use of `box<T>` to ensure that there is a break in the
        // chain of recursion, thereby allowing `Item` to include itself in its own definition.
        //
        // This is a table so that added fields, like for example a `hash`, can be easily added in
        // the future.
        2: store @generated_name("nested_store") table {
            1: items vector<box<Item>>;
        };
    }:optional;
};

/// An enumeration of things that may go wrong when trying to write a value to our store.
type WriteError = flexible enum {
    UNKNOWN = 0;
    INVALID_KEY = 1;
    INVALID_VALUE = 2;
    ALREADY_EXISTS = 3;
};

/// A very basic key-value store.
@discoverable
open protocol Store {
    /// Writes an item to the store.
    flexible WriteItem(struct {
        attempt Item;
    }) -> () error WriteError;
};
```

### CML

### Client

```
// Copyright 2022 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
{
    include: [ "syslog/client.shard.cml" ],
    program: {
        runner: "elf",
        binary: "bin/client_bin",
    },
    use: [
        { protocol: "examples.keyvaluestore.supporttrees.Store" },
        {
            config: "fuchsia.examples.keyvaluestore.supporttrees.WriteItems",
            key: "write_items",
            type: "vector",
            max_count: 16,
            element: {
                type: "string",
                max_size: 64,
            },
            availability: "transitional",
            default: [],
        },

        // A newline separated list nested entries. The first line should be the key
        // for the nested store, and each subsequent entry should be a pointer to a text file
        // containing the string value. The name of that text file (without the `.txt` suffix) will
        // serve as the entries key.
        {
            config: "fuchsia.examples.keyvaluestore.supporttrees.WriteNested",
            key: "write_nested",
            type: "vector",
            max_count: 16,
            element: {
                type: "string",
                max_size: 64,
            },
            availability: "transitional",
            default: [],
        },

        // A list of keys, all of which will be populated as null entries.
        {
            config: "fuchsia.examples.keyvaluestore.supporttrees.WriteNull",
            key: "write_null",
            type: "vector",
            max_count: 16,
            element: {
                type: "string",
                max_size: 64,
            },
            availability: "transitional",
            default: [],
        },

    ],
}
```

### Server

```
// Copyright 2022 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
{
    include: [ "syslog/client.shard.cml" ],
    program: {
        runner: "elf",
        binary: "bin/server_bin",
    },
    capabilities: [
        { protocol: "examples.keyvaluestore.supporttrees.Store" },
    ],
    expose: [
        {
            protocol: "examples.keyvaluestore.supporttrees.Store",
            from: "self",
        },
    ],
}
```

### Realm

```
// Copyright 2022 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
{
    children: [
        {
            name: "client",
            url: "#meta/client.cm",
        },
        {
            name: "server",
            url: "#meta/server.cm",
        },
    ],
    offer: [
        // Route the protocol under test from the server to the client.
        {
            protocol: "examples.keyvaluestore.supporttrees.Store",
            from: "#server",
            to: "#client",
        },

        // Route diagnostics support to all children.
        {
            dictionary: "diagnostics",
            from: "parent",
            to: [
                "#client",
                "#server",
            ],
        },
    ],
}
```

Client and server implementations can then be written in any supported language:

### Rust

### Client

```rust
// Copyright 2022 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

use {
    anyhow::{Context as _, Error},
    config::Config,
    fidl_examples_keyvaluestore_supporttrees::{Item, NestedStore, StoreMarker, Value},
    fuchsia_component::client::connect_to_protocol,
    std::{thread, time},
};

#[fuchsia::main]
async fn main() -> Result<(), Error> {
    println!("Started");

    // Load the structured config values passed to this component at startup.
    let config = Config::take_from_startup_handle();

    // Use the Component Framework runtime to connect to the newly spun up server component. We wrap
    // our retained client end in a proxy object that lets us asynchronously send `Store` requests
    // across the channel.
    let store = connect_to_protocol::<StoreMarker>()?;
    println!("Outgoing connection enabled");

    // This client's structured config has one parameter, a vector of strings. Each string is the
    // path to a resource file whose filename is a key and whose contents are a value. We iterate
    // over them and try to write each key-value pair to the remote store.
    for key in config.write_items.into_iter() {
        let path = format!("/pkg/data/{}.txt", key);
        let value = std::fs::read_to_string(path.clone())
            .with_context(|| format!("Failed to load {path}"))?;
        let res = store
            .write_item(&Item {
                key: key.clone(),
                value: Some(Box::new(Value::Bytes(value.into_bytes()))),
            })
            .await;
        match res? {
            Ok(_) => println!("WriteItem Success at key: {}", key),
            Err(err) => println!("WriteItem Error: {}", err.into_primitive()),
        }
    }

    // Add nested entries to the key-value store as well. The entries are strings, where the first
    // line is the key of the entry, and each subsequent entry should be a pointer to a text file
    // containing the string value. The name of that text file (without the `.txt` suffix) will
    // serve as the entries key.
    for spec in config.write_nested.into_iter() {
        let mut items = vec![];
        let mut nested_store = NestedStore::default();
        let mut lines = spec.split("\n");
        let key = lines.next().unwrap();

        // For each entry, make a new entry in the `NestedStore` being built.
        for entry in lines {
            let path = format!("/pkg/data/{}.txt", entry);
            let contents = std::fs::read_to_string(path.clone())
                .with_context(|| format!("Failed to load {path}"))?;
            items.push(Some(Box::new(Item {
                key: entry.to_string(),
                value: Some(Box::new(Value::Bytes(contents.into()))),
            })));
        }
        nested_store.items = Some(items);

        // Send the `NestedStore`, represented as a vector of values.
        let res = store
            .write_item(&Item {
                key: key.to_string(),
                value: Some(Box::new(Value::Store(nested_store))),
            })
            .await;
        match res? {
            Ok(_) => println!("WriteItem Success at key: {}", key),
            Err(err) => println!("WriteItem Error: {}", err.into_primitive()),
        }
    }

    // Each entry in this list is a null value in the store.
    for key in config.write_null.into_iter() {
        match store.write_item(&Item { key: key.to_string(), value: None }).await? {
            Ok(_) => println!("WriteItem Success at key: {}", key),
            Err(err) => println!("WriteItem Error: {}", err.into_primitive()),
        }
    }

    // TODO(https://fxbug.dev/42156498): We need to sleep here to make sure all logs get drained. Once the
    // referenced bug has been resolved, we can remove the sleep.
    thread::sleep(time::Duration::from_secs(2));
    Ok(())
}
```

### Server

```rust
// Copyright 2022 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

// Note: For the clarity of this example, allow code to be unused.
#![allow(dead_code)]

use {
    anyhow::{Context as _, Error},
    fidl_examples_keyvaluestore_supporttrees::{
        Item, StoreRequest, StoreRequestStream, Value, WriteError,
    },
    fuchsia_component::server::ServiceFs,
    futures::prelude::*,
    regex::Regex,
    std::cell::RefCell,
    std::collections::HashMap,
    std::collections::hash_map::Entry,
    std::str::from_utf8,
    std::sync::LazyLock,
};

static KEY_VALIDATION_REGEX: LazyLock<Regex> = LazyLock::new(|| {
    Regex::new(r"^[A-Za-z]\w+[A-Za-z0-9]$").expect("Key validation regex failed to compile")
});

// A representation of a key-value store that can contain an arbitrarily deep nesting of other
// key-value stores.
#[allow(clippy::box_collection, reason = "mass allow for https://fxbug.dev/381896734")]
enum StoreNode {
    Leaf(Option<Vec<u8>>),
    Branch(Box<HashMap<String, StoreNode>>),
}

/// Recursive item writer, which takes a `StoreNode` that may not necessarily be the root node, and
/// writes an entry to it.
fn write_item(
    store: &mut HashMap<String, StoreNode>,
    attempt: Item,
    path: &str,
) -> Result<(), WriteError> {
    // Validate the key.
    if !KEY_VALIDATION_REGEX.is_match(attempt.key.as_str()) {
        println!("Write error: INVALID_KEY, For key: {}", attempt.key);
        return Err(WriteError::InvalidKey);
    }

    // Write to the store, validating that the key did not already exist.
    match store.entry(attempt.key) {
        Entry::Occupied(entry) => {
            println!("Write error: ALREADY_EXISTS, For key: {}", entry.key());
            Err(WriteError::AlreadyExists)
        }
        Entry::Vacant(entry) => {
            let key = format!("{}{}", path, entry.key());
            match attempt.value {
                // Null entries are allowed.
                None => {
                    println!("Wrote value: NONE at key: {}", key);
                    entry.insert(StoreNode::Leaf(None));
                }
                Some(value) => match *value {
                    // If this is a nested store, recursively make a new store to insert at this
                    // position.
                    Value::Store(entry_list) => {
                        // Validate the value - absent stores, items lists with no children, or any
                        // of the elements within that list being empty boxes, are all not allowed.
                        if entry_list.items.is_some() {
                            let items = entry_list.items.unwrap();
                            if !items.is_empty() && items.iter().all(|i| i.is_some()) {
                                let nested_path = format!("{}/", key);
                                let mut nested_store = HashMap::<String, StoreNode>::new();
                                for item in items.into_iter() {
                                    write_item(&mut nested_store, *item.unwrap(), &nested_path)?;
                                }

                                println!("Created branch at key: {}", key);
                                entry.insert(StoreNode::Branch(Box::new(nested_store)));
                                return Ok(());
                            }
                        }

                        println!("Write error: INVALID_VALUE, For key: {}", key);
                        return Err(WriteError::InvalidValue);
                    }

                    // This is a simple leaf node on this branch.
                    Value::Bytes(value) => {
                        // Validate the value.
                        if value.is_empty() {
                            println!("Write error: INVALID_VALUE, For key: {}", key);
                            return Err(WriteError::InvalidValue);
                        }

                        println!("Wrote key: {}, value: {:?}", key, from_utf8(&value).unwrap());
                        entry.insert(StoreNode::Leaf(Some(value)));
                    }
                },
            }
            Ok(())
        }
    }
}

/// Creates a new instance of the server. Each server has its own bespoke, per-connection instance
/// of the key-value store.
async fn run_server(stream: StoreRequestStream) -> Result<(), Error> {
    // Create a new in-memory key-value store. The store will live for the lifetime of the
    // connection between the server and this particular client.
    let store = RefCell::new(HashMap::<String, StoreNode>::new());

    // Serve all requests on the protocol sequentially - a new request is not handled until its
    // predecessor has been processed.
    stream
        .map(|result| result.context("failed request"))
        .try_for_each(|request| async {
            // Match based on the method being invoked.
            match request {
                StoreRequest::WriteItem { attempt, responder } => {
                    println!("WriteItem request received");

                    // The `responder` parameter is a special struct that manages the outgoing reply
                    // to this method call. Calling `send` on the responder exactly once will send
                    // the reply.
                    responder
                        .send(write_item(&mut store.borrow_mut(), attempt, ""))
                        .context("error sending reply")?;
                    println!("WriteItem response sent");
                }
                StoreRequest::_UnknownMethod { ordinal, .. } => {
                    println!("Received an unknown method with ordinal {ordinal}");
                }
            }
            Ok(())
        })
        .await
}

// A helper enum that allows us to treat a `Store` service instance as a value.
enum IncomingService {
    Store(StoreRequestStream),
}

#[fuchsia::main]
async fn main() -> Result<(), Error> {
    println!("Started");

    // Add a discoverable instance of our `Store` protocol - this will allow the client to see the
    // server and connect to it.
    let mut fs = ServiceFs::new_local();
    fs.dir("svc").add_fidl_service(IncomingService::Store);
    fs.take_and_serve_directory_handle()?;
    println!("Listening for incoming connections");

    // The maximum number of concurrent clients that may be served by this process.
    const MAX_CONCURRENT: usize = 10;

    // Serve each connection simultaneously, up to the `MAX_CONCURRENT` limit.
    fs.for_each_concurrent(MAX_CONCURRENT, |IncomingService::Store(stream)| {
        run_server(stream).unwrap_or_else(|e| println!("{:?}", e))
    })
    .await;

    Ok(())
}
```

### C++ (Natural)

### Client

```c++
// TODO(https://fxbug.dev/42060656): C++ (Natural) implementation.
```

### Server

```c++
// TODO(https://fxbug.dev/42060656): C++ (Natural) implementation.
```

### C++ (Wire)

### Client

```c++
// TODO(https://fxbug.dev/42060656): C++ (Wire) implementation.
```

### Server

```c++
// TODO(https://fxbug.dev/42060656): C++ (Wire) implementation.
```


<br />

## fi-0194

> [!WARNING]
> **Deprecated:** This error code has been retired.

## fi-0195

> [!WARNING]
> **Deprecated:** This error code has been retired.

## fi-0196

> [!WARNING]
> **Deprecated:** This error code has been retired.

## fi-0200

> [!WARNING]
> **Deprecated:** This error code has been retired.

## fi-0201: Platform version not selected

This error occurs when you compile a versioned FIDL library without choosing a
version:

> [!WARNING]
> **Incorrect**

    // fidlc --files test.fidl --out test.json
    @available(platform="foo", added=1)
    library test.bad.fi0201;

To fix it, choose a version with the `--available` command line flag:

> [!TIP]
> **Correct**

    // fidlc --files test.fidl --out test.json --available foo:1
    @available(platform="foo", added=1)
    library test.good.fi0201;

The version must be a number greater than or equal to 1, or one of the special
versions `NEXT` and `HEAD`. For more information, see the documentation for
[FIDL versioning](https://fuchsia.dev/docs/reference/fidl/language/versioning).

## fi-0202

> [!WARNING]
> **Deprecated:** This error code has been retired.

## fi-0203: Removed and replaced are mutually exclusive

The `@available` attribute supports the arguments `removed` and `replaced`, but
they can't be used together:

> [!WARNING]
> **Incorrect**

    @available(added=1)
    library test.bad.fi0203;

    protocol Foo {
        @available(removed=2, replaced=2)
        Foo();
    };

To fix the error, delete one of the arguments. If you intend to remove the
element without replacing it, keep `removed` and delete `replaced`:

    @available(added=1)
    library test.good.fi0203a;

    open protocol Foo {
        @available(removed=2)
        strict Foo();
    };

Alternatively, if you are [swapping](https://fuchsia.dev/docs/reference/fidl/language/versioning#swapping) the element with a new definition, keep
`replaced` and delete `removed`:

> [!TIP]
> **Correct**

    @available(added=1)
    library test.good.fi0203b;

    open protocol Foo {
        @available(replaced=2)
        strict Foo();

        @available(added=2)
        flexible Foo();
    };

It doesn't make sense to use `removed` and `replaced` together because they have
opposite meanings. When an element is marked `removed`, fidlc validates that
there **IS NOT** a replacement element added at the same version. When an
element is marked `replaced`, fidlc validates that there **IS** a replacement
element added at the same version.

See [FIDL versioning](https://fuchsia.dev/docs/reference/fidl/language/versioning) to learn more about versioning.

## fi-0204: Library cannot be replaced

The `@available` attribute's `replaced` argument cannot be used on a library
declaration:

> [!WARNING]
> **Incorrect**

    @available(added=1, replaced=2)
    library test.bad.fi0204;

Instead, use the `removed` argument:

> [!TIP]
> **Correct**

    @available(added=1, removed=2)
    library test.good.fi0204;

The `replaced` argument indicates that an element is replaced by a new
definition. This is not supported for an entire library, since we assume each
library only has one set of files that defines it.

See [FIDL versioning](https://fuchsia.dev/docs/reference/fidl/language/versioning) to learn more about versioning.

## fi-0205: Invalid `@available(removed=N)`

When an element is marked `@available(removed=N)`, it means the element can no
longer be used at version `N`. You cannot reuse its name:

> [!WARNING]
> **Incorrect**

    @available(added=1)
    library test.bad.fi0204;

    open protocol Foo {
        @available(removed=2)
        strict Bar();
        @available(added=2)
        flexible Bar();
    };

If you want to replace the element with a new definition (same API and ABI), use
the `replaced` argument instead of the `removed` argument:

> [!TIP]
> **Correct**

    @available(added=1)
    library test.good.fi0204a;

    open protocol Foo {
        @available(replaced=2)
        strict Bar();
        @available(added=2)
        flexible Bar();
    };

If you want to remove the element and define a new, unrelated element (different
API and ABI), choose a different name for the new element:

> [!TIP]
> **Correct**

    @available(added=1)
    library test.good.fi0204b;

    open protocol Foo {
        @available(removed=2)
        strict Bar();
        @available(added=2)
        flexible NewBar();
    };

If you really want to reuse the name (same API, different ABI), use the
`renamed` argument to rename the old element post-removal, freeing up its
original name:

> [!TIP]
> **Correct**

    @available(added=1)
    library test.good.fi0204c;

    open protocol Foo {
        @available(removed=2, renamed="DeprecatedBar")
        strict Bar();

        @available(added=2)
        @selector("NewBar")
        flexible Bar();
    };

Notice that in this case you must use `@selector` to ensure the new method has a
different ABI.

See [FIDL versioning](https://fuchsia.dev/docs/reference/fidl/language/versioning) to learn more about versioning.

## fi-0206: Invalid `@available(replaced=N)`

When an element is marked `@available(replaced=N)`, it means the element is
replaced by a new definition marked `@available(added=N)`. The FIDL compiler
will report an error if it cannot find such a definition:

> [!WARNING]
> **Incorrect**

    @available(added=1)
    library test.bad.fi0205;

    open protocol Foo {
        @available(replaced=2)
        strict Bar();
    };

If you did not intend to replace the element, use the `removed` argument instead
of the `replaced` argument:

> [!TIP]
> **Correct**

    @available(added=1)
    library test.good.fi0205a;

    open protocol Foo {
        @available(removed=2)
        strict Bar();
    };

If you intended to replace the element, add a replacement definition:

> [!TIP]
> **Correct**

    @available(added=1)
    library test.good.fi0205b;

    open protocol Foo {
        @available(replaced=2)
        strict Bar();
        @available(added=2)
        flexible Bar();
    };

See [FIDL versioning](https://fuchsia.dev/docs/reference/fidl/language/versioning) to learn more about versioning.

## fi-0207: Type shape integer overflow

A FIDL type must not be so large that its size overflows `uint32`:

> [!WARNING]
> **Incorrect**

    library test.bad.fi0207;

    type Foo = struct {
        bytes array<uint64, 536870912>;
    };

To fix the error, use a smaller array size:

> [!TIP]
> **Correct**

    library test.good.fi0207;

    type Foo = struct {
        bytes array<uint64, 100>;
    };

In practice FIDL types should be far smaller than 2^32^ bytes, because
they are usually sent over Zircon channels, which are limited to [64 KiB per
message](https://fuchsia.dev/reference/syscalls/channel_write).

## fi-0208: Reserved platform

Certain platform names are reserved by FIDL. For example, the "unversioned"
platform is reserved to represent libraries that don't use versioning:

> [!WARNING]
> **Incorrect**

    @available(platform="unversioned", added=1)
    library test.bad.fi0208;

Choose a different platform name instead:

> [!TIP]
> **Correct**

    @available(platform="foo", added=1)
    library test.good.fi0208;

See [FIDL versioning](https://fuchsia.dev/docs/reference/fidl/language/versioning) to learn more about versioning.

## fi-0209: Reserved fields are not allowed

FIDL no longer supports `reserved` table or union fields:

> [!WARNING]
> **Incorrect**

    library test.bad.fi0209;

    type User = table {
        1: reserved;
        2: email string;
    };

The main purpose of reserved fields was to avoid accidental reuse of ordinals.
With [FIDL versioning](https://fuchsia.dev/docs/reference/fidl/language/versioning), that is no
longer an issue. You can annotate old fields `@available(removed=N)` while
keeping them (and their ordinals) in the source file:

> [!TIP]
> **Correct**

    @available(added=1)
    library test.good.fi0209a;

    type User = table {
        @available(removed=2)
        1: name string;
        2: email string;
    };

Another use of `reserved` was to document the intended future use of an ordinal.
In that case, consider defining the field at the unstable API level `HEAD`:

> [!TIP]
> **Correct**

    @available(added=1)
    library test.good.fi0209b;

    type User = table {
        @available(added=HEAD)
        1: name string;
        2: email string;
    };

For any other uses of `reserved`, consider leaving a comment instead:

> [!TIP]
> **Correct**

    library test.good.fi0209c;

    type User = table {
        // We skip ordinal 1 because...
        2: email string;
    };

## fi-0210: Invalid location in @discoverable client or server argument

The allowed `client` or `server` location for a discoverable protocol must be a
(possibly empty) comma separated list of `platform` and `external`. In other words one of:
- `""`
- `"platform"`
- `"external"`
- `"platform,external"`
- `"external,platform"`

> [!WARNING]
> **Incorrect**

    library test.bad.fi0210;

    @discoverable(server="platform,canada")
    protocol Example {};

Make sure these arguments are correct:

> [!TIP]
> **Correct**

    library test.good.fi0210;

    @discoverable(server="platform")
    protocol Example {};

## fi-0211: Element cannot be renamed

The `@available` attribute's `renamed` argument can only be used on members of
declarations, not on declarations themselves:

> [!WARNING]
> **Incorrect**

    @available(added=1)
    library test.bad.fi0211;

    @available(replaced=2, renamed="Bar")
    type Foo = struct {};

    @available(added=2)
    type Bar = struct {};

Instead of renaming a declaration, remove the old one and add a new one:

> [!TIP]
> **Correct**

    @available(added=1)
    library test.good.fi0211;

    @available(removed=2)
    type Foo = struct {};

    @available(added=2)
    type Bar = struct {};

Renaming is only supported on members because the FIDL compiler can compare
their ABI identity (e.g. table ordinal) to ensure it is done correctly.

The `renamed` argument is also not allowed on the following elements either:

- `library`: You can't rename a library from within because the FIDL toolchain assumes each library has a single name. Instead, you should create a new library with the desired name and migrate users to it.
- `compose`: You can't rename a protocol composition because compositions are not named to begin with.

See [FIDL versioning](https://fuchsia.dev/docs/reference/fidl/language/versioning) to learn more about versioning.

## fi-0212: Renamed without replaced or removed

The `@available` argument `renamed` is not allowed on its own. It must be used
together with the `replaced` or `removed` argument:

> [!WARNING]
> **Incorrect**

    @available(added=1)
    library test.bad.fi0212;

    protocol Foo {
        @available(renamed="New")
        Old();
    };

If you just want to rename the element at version `N`, use `replaced=N` and
define a replacement with the new name marked `added=N`:

> [!TIP]
> **Correct**

    @available(added=1)
    library test.good.fi0212a;

    protocol Foo {
        @available(replaced=2, renamed="New")
        Old();

        @available(added=2)
        @selector("Old")
        New();
    };

In this case, the replacement method must override `@selector` for ABI
compatibility.

Alternatively, if you want to remove the element at version `N` and refer to it
by a different name after its removal, use `removed=N`:

> [!TIP]
> **Correct**

    @available(added=1)
    library test.good.fi0212b;

    protocol Foo {
        @available(removed=2, renamed="DeprecatedOld")
        Old();
    };

In this case, the new name will only be used when targeting multiple versions
(e.g. `--available test:1,2`) since that is the only way to include the element
while also targeting a version past its removal.

See [FIDL versioning](https://fuchsia.dev/docs/reference/fidl/language/versioning) to learn more about versioning.

## fi-0213: Renamed to same name

When renaming an element with the `@available` argument `renamed`, the new name
cannot be the same as the element's original name:

> [!WARNING]
> **Incorrect**

    @available(added=1)
    library test.bad.fi0213;

    type Foo = table {
        @available(replaced=2, renamed="bar")
        1: bar string;
        @available(added=2)
        1: bar string:10;
    };

To fix the error, remove the `renamed` argument:

> [!TIP]
> **Correct**

    @available(added=1)
    library test.good.fi0213a;

    type Foo = table {
        @available(replaced=2)
        1: bar string;
        @available(added=2)
        1: bar string:10;
    };

Alternatively, keep the `renamed` argument but choose a different name:

> [!TIP]
> **Correct**

    @available(added=1)
    library test.good.fi0213b;

    type Foo = table {
        @available(replaced=2, renamed="baz")
        1: bar string;
        @available(added=2)
        1: baz string:10;
    };

See [FIDL versioning](https://fuchsia.dev/docs/reference/fidl/language/versioning) to learn more about versioning.

## fi-0214: Invalid `@available(removed=N, renamed="NewName")`

This is like [fi-0205: Invalid `@available(removed=N)`](https://fuchsia.dev/fuchsia-src/reference/fidl/language/errcat#fi-0205), but for when
the `renamed` argument is involved.

When an element is marked `@available(removed=N, renamed="NewName")`, it means
the element can no longer be used at version `N`, and is renamed to "NewName"
post-removal. You cannot use "NewName" for something else:

> [!WARNING]
> **Incorrect**

    @available(added=1)
    library test.bad.fi0214;

    open protocol Foo {
        @available(removed=2, renamed="NewName")
        strict OldName();

        @available(added=2)
        flexible NewName();
    };

If you want to rename the element while keeping its ABI, use the `replaced`
argument instead of the `removed` argument:

> [!TIP]
> **Correct**

    @available(added=1)
    library test.good.fi0214a;

    open protocol Foo {
        @available(replaced=2, renamed="NewName")
        strict OldName();

        @available(added=2)
        @selector("OldName")
        flexible NewName();
    };

Notice that in this case you must use `@selector` to ensure the renamed method
has the same ABI.

If you want the new element to have a different ABI, then keep `removed` and
ensure that the `renamed` argument and the new element use different names:

> [!TIP]
> **Correct**

    @available(added=1)
    library test.good.fi0214b;

    open protocol Foo {
        @available(removed=2, renamed="NewName")
        strict OldName();

        @available(added=2)
        strict DifferentName();
    };

See [FIDL versioning](https://fuchsia.dev/docs/reference/fidl/language/versioning) to learn more about versioning.

## fi-0215: Invalid `@available(replaced=N, renamed="NewName")`

This is like [fi-0206: Invalid `@available(replaced=N)`](https://fuchsia.dev/fuchsia-src/reference/fidl/language/errcat#fi-0206), but for when
the `renamed` argument is involved.

When an element is marked `@available(replaced=N, renamed="NewName")`, it means
the element is replaced by a new definition named "NewName" and marked with
`@available(added=N)`. The FIDL compiler will report an error if it cannot find
such a definition:

> [!WARNING]
> **Incorrect**

    @available(added=1)
    library test.bad.fi0215;

    open protocol Foo {
        @available(replaced=2, renamed="NewName")
        strict OldName();
    };

To fix the error, define an element with the new name:

> [!TIP]
> **Correct**

    @available(added=1)
    library test.good.fi0215;

    open protocol Foo {
        @available(replaced=2, renamed="NewName")
        strict OldName();

        @available(added=2)
        @selector("OldName")
        strict NewName();
    };

Notice that you must use `@selector` to ensure the renamed method has the same
ABI.

See [FIDL versioning](https://fuchsia.dev/docs/reference/fidl/language/versioning) to learn more about versioning.

## fi-0216: Invalid `@available(removed=N)` (ABI)

This is like [fi-0205: Invalid `@available(removed=N)`](https://fuchsia.dev/fuchsia-src/reference/fidl/language/errcat#fi-0205), but instead
of the element's name being reused, its ABI is:

> [!WARNING]
> **Incorrect**

    @available(added=1)
    library test.bad.fi0216;

    open protocol Foo {
        @available(removed=2)
        strict Bar();

        @available(added=2)
        @selector("Bar")
        flexible Qux();
    };

If you are intentionally replacing the element's ABI, make it explicit by using
the arguments `replaced` and `renamed` instead of `removed`:

> [!TIP]
> **Correct**

    @available(added=1)
    library test.good.fi0216a;

    open protocol Foo {
        @available(replaced=2, renamed="Qux")
        strict Bar();

        @available(added=2)
        @selector("Bar")
        flexible Qux();
    };

If you did not intend to reuse the ABI, choose a different one. In this case, we
can remove the `@selector` attribute and use the method's default selector based
on its name:

> [!TIP]
> **Correct**

    @available(added=1)
    library test.good.fi0216b;

    open protocol Foo {
        @available(removed=2)
        strict Bar();

        @available(added=2)
        flexible Qux();
    };

This error can occur for other members, not just methods. For bits and enum
members, the ABI is the integer value. For struct members, the ABI is the byte
offset. For table and union members, the ABI is the ordinal.

See [FIDL versioning](https://fuchsia.dev/docs/reference/fidl/language/versioning) to learn more about versioning.

## fi-0217: Invalid `@available(replaced=N)` (ABI)

This is like [fi-0206: Invalid `@available(replaced=N)`](https://fuchsia.dev/fuchsia-src/reference/fidl/language/errcat#fi-0206), but for when
a replacement is only found matching the element's name, not its ABI:

> [!WARNING]
> **Incorrect**

    @available(added=1)
    library test.bad.fi0217;

    open protocol Foo {
        @available(replaced=2)
        strict Bar();

        @available(added=2)
        @selector("NotBar")
        flexible Bar();
    };

If you intended to replace the element, make sure its ABI matches. In this case,
we can remove the `@selector` attribute since both methods already have the same
name:

> [!TIP]
> **Correct**

    @available(added=1)
    library test.good.fi0217a;

    open protocol Foo {
        @available(replaced=2)
        strict Bar();

        @available(added=2)
        flexible Bar();
    };

If you did not intend to replace the ABI, use `removed` instead of `replaced`.
In this case, we also have to choose a different name to avoid clashing with the
old one:

> [!TIP]
> **Correct**

    @available(added=1)
    library test.good.fi0217b;

    open protocol Foo {
        @available(removed=2)
        strict Bar();

        @available(added=2)
        flexible NotBar();
    };

If you really want to reuse the name but not the ABI, use `removed` instead of
`replaced`, and also use `renamed` to rename the old element post-removal,
freeing up its original name:

> [!TIP]
> **Correct**

    @available(added=1)
    library test.good.fi0217c;

    open protocol Foo {
        @available(removed=2, renamed="DeprecatedBar")
        strict Bar();

        @available(added=2)
        @selector("NotBar")
        flexible Bar();
    };

This error can occur for other members, not just methods. For bits and enum
members, the ABI is the integer value. For struct members, the ABI is the byte
offset. For table and union members, the ABI is the ordinal.

See [FIDL versioning](https://fuchsia.dev/docs/reference/fidl/language/versioning) to learn more about versioning.

## fi-0218: Invalid modifier availability argument

In the FIDL versioning [modifier syntax](https://fuchsia.dev/docs/reference/fidl/language/versioning#modifiers), you can only use the arguments `added`
and `removed`. Other `@available` arguments like `deprecated` are not allowed:

> [!WARNING]
> **Incorrect**

    @available(added=1)
    library test.bad.fi0218;

    type Foo = resource(deprecated=2) struct {};

To fix the error, remove the unsupported argument:

> [!TIP]
> **Correct**

    @available(added=1)
    library test.good.fi0218;

    type Foo = resource struct {};

Unlike declarations and members, modifiers do not have lifecycles of their own,
so concepts like deprecation, replacement, and renaming do not make sense for
them. Modifiers can only be added and removed.

See [FIDL versioning](https://fuchsia.dev/docs/reference/fidl/language/versioning) to learn more about versioning.

## fi-0219: Cannot change method strictness

The FIDL versioning [modifier syntax](https://fuchsia.dev/docs/reference/fidl/language/versioning#modifiers) lets you add or remove `strict` and
`flexible` modifiers. However, this is not allowed on a two-way method if it
doesn't use the `error` syntax, because such a change would be ABI breaking:

> [!WARNING]
> **Incorrect**

    @available(added=1)
    library test.bad.fi0219;

    open protocol Foo {
        strict(removed=2) flexible(added=2) Method() -> ();
    };

Instead, remove the strict method and add a flexible method with a different
name to replace it:

> [!TIP]
> **Correct**

    @available(added=1)
    library test.good.fi0219a;

    open protocol Foo {
        @available(removed=2)
        strict Method() -> ();

        @available(added=2)
        flexible NewMethod() -> ();
    };

Alternatively, you can [use the `renamed` argument and `@selector`
attribute](https://fuchsia.dev/docs/reference/fidl/language/versioning#after-removal) if you want to reuse the method name for the new ABI:

> [!TIP]
> **Correct**

    @available(added=1)
    library test.good.fi0219b;

    open protocol Foo {
        @available(removed=2, renamed="StrictMethod")
        strict Method() -> ();

        @available(added=2)
        @selector("FlexibleMethod")
        flexible Method() -> ();
    };

Changing the strictness of a two-way method without error syntax is not allowed
because it would change the shape of the response. When a two-way method is
flexible or uses error syntax, FIDL automatically generates a result union that
wraps the response. Therefore, changing strictness is only safe for two-way
methods that have error syntax.

See [FIDL versioning](https://fuchsia.dev/docs/reference/fidl/language/versioning) to learn more about versioning.

## fi-0220: Name not found in version range

This error occurs when a name cannot be found at a particular version, but it is
found in other versions. For example, an element `Foo` added at version 1 cannot
reference another element `Bar` added at version 2, because `Bar` does not exist
at version 1:

> [!WARNING]
> **Incorrect**

    @available(added=1)
    library test.bad.fi0220;

    alias Foo = Bar;

    @available(added=2)
    type Bar = struct {};

In this case, we can fix the error add an `@available` attribute to make `Foo`
added at version 2 as well:

> [!TIP]
> **Correct**

    @available(added=1)
    library test.good.fi0220;

    @available(added=2)
    alias Foo = Bar;

    @available(added=2)
    type Bar = struct {};

See [FIDL versioning](https://fuchsia.dev/docs/reference/fidl/language/versioning) to learn more about versioning.

## fi-0221: `resource` appears in declaration annotated `@no_resource`

This error occurs when a declaration has the `@no_resource` attribute but some
item within it has the `resource` modifier.

> [!WARNING]
> **Incorrect**

    library test.bad.fi0221;

    @no_resource
    open protocol Foo {
        flexible Bar(resource struct {
            a uint8;
        });
    };

You can fix the error by either removing the attribute or removing the resource
modifier.

> [!TIP]
> **Correct**

    library test.good.fi0221;

    @no_resource
    open protocol Foo {
        flexible Bar(struct {
            a uint8;
        });
    };

## fi-0222: `@no_resource` is an experimental attribute

The `@no_resource` annotation is experimental and only meant to be used by a few
specific protocols.

> [!WARNING]
> **Incorrect**

    library test.bad.fi0222;

    @no_resource
    type Foo = struct {
        a uint32;
    };

The annotation activates new compiler errors but doesn't have any effect on
semantics. It should be fine to just remove it.

> [!TIP]
> **Correct**

    library test.good.fi0222;

    type Foo = struct {
        a uint32;
    };

## fi-0223: protocol has the `@no_resource` attribute and thus cannot compose other protocol

This error occurs when a protocol that is annotated `@no_resource` composes
another protocol which is not annotated in that way.

> [!WARNING]
> **Incorrect**

    library test.bad.fi0223;

    open protocol A {
        flexible F();
    };

    @no_resource
    open protocol B {
        compose A;
        flexible G();
    };

To fix, add `@no_resource` to the composed protocol.

> [!TIP]
> **Correct**

    library test.good.fi0223;

    @no_resource
    open protocol A {
        flexible F();
    };

    @no_resource
    open protocol B {
        compose A;
        flexible G();
    };

## fi-0224: Cannot be non-zero

This error occurs when you try to mark a type as non-zero that cannot be non-zero.

> [!WARNING]
> **Incorrect**

    library test.bad.fi0224;

    type Bar = struct {
        foo float32:nonzero;
    };

To fix this error, remove the non-zero constraint:

> [!TIP]
> **Correct**

    library test.good.fi0224;

    type Bar = struct {
        foo float32;
    };

Only integral FIDL types may be constrained to non-zero values.

## fi-0225: Type cannot be marked as non-zero twice

This error occurs when a type is made non-zero twice. Usually, this occurs when the type is marked non-zero at both its use and declaration sites.

> [!WARNING]
> **Incorrect**

    library test.bad.fi0225;

    alias MyAlias = int32:nonzero;

    type MyStruct = struct {
        my_member MyAlias:nonzero;
    };

To fix this error, only make the type non-zero once.

For example, you can remove `:nonzero` from the use site.

> [!TIP]
> **Correct**

    library test.good.fi0225a;

    alias MyAlias = int32:nonzero;

    type MyStruct = struct {
        my_member MyAlias;
    };

You could also remove `:nonzero` from the alias declaration.

    library test.good.fi0225b;

    alias MyAlias = int32;

    type MyStruct = struct {
        my_member MyAlias:nonzero;
    };

## fi-0226: Invalid value for non-zero constant

A constant value may not be zero if its underlying type is constrained to non-zero values:

> [!WARNING]
> **Incorrect**

    library test.bad.fi0226;

    const FOO uint8:nonzero = 0;
    const BAR int32:nonzero = 0;

The problem may be fixed either by changing the value to fit within the type's range:

> [!TIP]
> **Correct**

    library test.good.fi0226a;

    const FOO uint8:nonzero = 1;
    const BAR int32:nonzero = 4;

Or otherwise by changing the type to accommodate the zero value:

> [!TIP]
> **Correct**

    library test.good.fi0226b;

    const FOO uint8 = 0;
    const BAR int32 = 0;

[](https://issues.fuchsia.dev/issues/new?component=1439230&template=1881640&description=Issue+on:+https://fuchsia.dev/docs/reference/fidl/language/errcat.md "Report a bug or suggest improvements on this page") [](https://cs.opensource.google/fuchsia/fuchsia/+/main:docs/reference/fidl/language/errcat.md "View the source code of this page") [](https://ci.android.com/edit?repo=fuchsia/fuchsia/main&file=docs/reference/fidl/language/errcat.md&cloneRepo=fuchsia/fuchsia:refs/heads/main&fullPath=fuchsia/docs/reference/fidl/language/errcat.md "Edit the source code of this page")