A proto3 message
The Avro record it becomes, and where the two type systems do not line up
syntax = "proto3";
message User {
int32 id = 1;
string email_address = 2;
}
Convert a .proto to an Avro schema, and get told what did not
survive. Unsigned 64-bit types have no Avro equivalent, enums renumber when
they are sparse, and a singular proto3 scalar has no presence to map onto a
nullable union.
The root message becomes the top-level Avro record. Everything it reaches is emitted inline at its first use, and a second reference becomes a name, which is what makes a recursive message representable.
Or drop a file anywhere on this panel. Nothing is uploaded: the analysis runs in this tab.
The answer appears here
Paste on the left and press Convert. Nothing leaves this tab.
Nothing else to flag.
No formatting problems, and nothing the rules object to. Worth remembering what that covers: this reads the file you pasted, not the account or cluster it will be applied to.
No finding matches that filter.
Real input you can load into the tool above. Each one shows a different thing going wrong, because that is what the tool is for.
The Avro record it becomes, and where the two type systems do not line up
syntax = "proto3";
message User {
int32 id = 1;
string email_address = 2;
}How proto enums and repeated fields map, including the zero-value rule
syntax = "proto3";
enum Status {
UNKNOWN = 0;
ACTIVE = 1;
}
message Order {
Status status = 1;
repeated string tags = 2;
}These are the ones that fail silently. The config is accepted, nothing raises an error, and the consequence arrives later.
Proto3 scalars have no null. A field left unset is the zero value, which is not the same as an Avro null union.
Instead:Decide per field whether absence means null or zero, and encode that deliberately.
Proto enums require a zero value and allow unknown values through. Avro enums are closed and reject anything unlisted.
Instead:Map to a string, or include a default symbol.
Protobuf identifies fields by number and Avro by name and position. A rename is safe in protobuf and breaking in Avro.
Instead:Keep names stable when both formats are in play.
Both formats describe records of typed fields, so most of a schema converts without a decision to make. A converter is worth a page for the parts that do not, because a schema the registry accepts and the data does not fit is worse than a failed conversion.
Avro's long is signed 64-bit, so uint64 and fixed64 cannot be represented: every value above 9223372036854775807 has nowhere to go. Avro has no unsigned types and nothing wider, so there is no lossless choice to offer. uint32 and fixed32 have a milder version of the same problem, since Avro's int is signed 32-bit, and they widen to long, which is lossless but changes the generated Java accessor from int to long.
A protobuf enum is a name-to-number mapping and the number is what goes on the wire. An Avro enum is an ordered list of symbols and the ordinal is what goes on the wire. The two agree only when the protobuf numbers happen to be 0, 1, 2 in declaration order. An enum numbered 0, 5, 9 becomes 0, 1, 2 in Avro, so every symbol after the first gap silently changes value. This is reported with the actual numbers rather than as a general warning.
A singular proto3 scalar cannot tell unset from zero, so there is nothing to map a nullable union onto: it becomes a plain Avro field with the type's default, which is the closest true statement. A field declared optional does have presence and becomes ["null", T] with a default of null. So does a message field, and so does a wrapper type, which is the one well-known type that maps onto Avro exactly. Adding optional in the .proto and converting again is the way to get a nullable Avro field.
google.protobuf.Timestamp carries seconds plus nanoseconds. Avro's finest timestamp logical type is microseconds, so the last three digits are dropped. google.protobuf.Duration is worse: Avro's duration is a twelve-byte fixed of months, days and milliseconds, which cannot express a signed span of seconds and nanos at all, so it is converted to a record of seconds and nanos instead, which is lossless but is not Avro's own type.
Every schema this produces is parsed back before it is shown, using the same parser the Avro validator and compatibility checker on this site read through. That is a rule every generator here follows, and it is not decoration: it caught a union nested inside another union in this converter, which Avro forbids and which the wrapper types produce if the nullable wrapping does not flatten.
Anything behind an import, since it reads one file. Whether the registry will accept the result under your compatibility setting, which depends on the version already registered rather than on the schema alone: the compatibility checker on this site answers that once you have both. It also does not convert data, only the schema.