Migration Guide
Changes in v30.0
The following is a list of the breaking changes made to versions of the libraries, and how to update your code to accommodate the changes.
This covers breaking changes announced in News Announcements for v30.x and Release Notes for v30.0.
Replaced CMake Submodules with Fetched Deps
Previously, our default CMake behavior was to use Git submodules to grab pinned
dependencies. Specifying -Dprotobuf_ABSL_PROVIDER=package
would flip our CMake
configs to look for local installations of Abseil (with similar options for
jsoncpp and gtest). These options no longer exist, and the default behavior is
to first look for installations of all our dependencies, falling back to
fetching pinned versions from GitHub if needed.
To prevent any fallback fetching (similar to the old package
behavior), you
can call CMake with:
cmake . -Dprotobuf_LOCAL_DEPENDENCIES_ONLY=ON
To always fetch dependencies from a fixed version (similar to the old default behavior), you can call CMake with:
cmake . -Dprotobuf_FORCE_FETCH_DEPENDENCIES=ON
string_view return type
Return types are now absl::string_view
for the following descriptor APIs,
which opens up memory savings:
MessageLite::GetTypeName
UnknownField::length_delimited
- Descriptor API name functions, such as
FieldDescriptor::full_name
We expect future breaking releases to continue migrating additional APIs to
absl::string_view
.
In most cases, you should try to update types to use absl::string_view
where
safe, or explicitly copy to the original type where needed. You may need to
update callers as well if this is returned in a function.
If the string returned by the affected API methods is being used as:
Type | Migration |
---|---|
| Explicitly convert to Or, switch to the more performant |
| Migrate to If infeasible (such as due to large number of dependencies), copying to a |
| If nullable, migrate to Otherwise, migrate to Be careful when calling |
For common containers and other APIs, you may be able to migrate to variants
compatible with absl::string_view
. Below are some common examples.
Category | Pre-Migration | Migration |
---|---|---|
Insertion into std::vector<std::string> |
|
|
Insertion for map or sets |
|
|
Lookup for map or sets |
| Migrate to Abseil containers. Or, define a transparent comparator.
|
String Concatenation |
|
These are recommended for performance reasons anyways. See https://abseil.io/tips/3. |
See also https://abseil.io/tips/1 for general tips
around using absl::string_view
.
Poison MSVC + Bazel
Bazel users on Windows should switch to using clang-cl by adding the following to their project, like in this example.
.bazelrc
common --enable_platform_specific_config build:windows
--extra_toolchains=@local_config_cc//:cc-toolchain-x64_windows-clang-cl
--extra_execution_platforms=//:x64_windows-clang-cl
MODULE.bazel
bazel_dep(name = "platforms", version = "0.0.10")
bazel_dep(name = "rules_cc", version = "0.0.17")
# For clang-cl configuration
cc_configure = use_extension("@rules_cc//cc:extensions.bzl", "cc_configure_extension")
use_repo(cc_configure, "local_config_cc")
WORKSPACE
load("//:protobuf_deps.bzl", "PROTOBUF_MAVEN_ARTIFACTS", "protobuf_deps")
protobuf_deps()
load("@rules_cc//cc:repositories.bzl", "rules_cc_dependencies", "rules_cc_toolchains")
rules_cc_dependencies()
rules_cc_toolchains()
BUILD
For users that need compatibility with Bazel 8 only.
platform(
name = "x64_windows-clang-cl",
constraint_values = [
"@platforms//cpu:x86_64",
"@platforms//os:windows",
"@bazel_tools//tools/cpp:clang-cl",
],
)
For users that need compatibility with Bazel 7 and 8.
platform(
name = "x64_windows-clang-cl",
constraint_values = [
"@platforms//cpu:x86_64",
"@platforms//os:windows",
# See https://github.com/bazelbuild/rules_cc/issues/330.
"@rules_cc//cc/private/toolchain:clang-cl",
],
)
Users can also temporarily silence the error by setting the opt-out flag
--define=protobuf_allow_msvc=true
until the next breaking release.
Alternatively, users that wish to continue using MSVC may switch to using CMake. This can be done with Visual Studio, or by supplying the CMake command-line an MSVC generator. For example:
cmake -G "Visual Studio 17 2022" -A Win64 .
ctype Removed from FieldDescriptor Options
We stopped exposing the ctype
from FieldDescriptor
options. You can use the
FieldDescriptor::cpp_string_type()
API, added in the
v28 release,
in its place.
Modified Debug APIs to Redact Sensitive Fields
The Protobuf C++ debug APIs (including Protobuf AbslStringify,
proto2::ShortFormat
, proto2::Utf8Format
, Message::DebugString
,
Message::ShortDebugString
, Message::Utf8DebugString
) changed to redact
sensitive fields annotated by debug_redact
; the outputs of these APIs contain
a per-process randomized prefix, and are no longer parseable by Protobuf
TextFormat Parsers. Users should adopt the new redacted debug format for most
cases requiring a human-readable output (such as logging), or consider switching
to binary format for serialization and deserialization. Users who need the old
deserializable format can use TextFormat.printer().printToString(proto)
, but
this does not redact sensitive fields and so should be used with caution.
Read more about this in the news article released December 4, 2024.
Removed Deprecated APIs
We removed the following public runtime APIs, which have been marked deprecated
(such as ABSL_DEPRECATED
) for at least one minor or major release and that are
obsolete or replaced.
API:
Arena::CreateMessage
Replacement:
Arena::Create
API:
Arena::GetArena
Replacement: value->GetArena()
API:
RepeatedPtrField::ClearedCount
Replacement: Migrate to Arenas (migration guide).
API:
JsonOptions
Replacement: JsonPrintOptions
Dropped C++14 Support
This release dropped C++ 14 as the minimum supported version and raised it to 17, as per the Foundational C++ Support matrix.
Users should upgrade to C++17.
Introduced ASAN Poisoning After Clearing Oneof Messages on Arena
This change added a hardening check that affects C++ protobufs using Arenas. Oneof messages allocated on the protobuf arena are now cleared in debug and poisoned in ASAN mode. After calling clear, future attempts to use the memory region will cause a crash in ASAN as a use-after-free error.
This implementation requires C++17.
Dropped our C++ CocoaPods release
We dropped our C++ CocoaPods release, which has been broken since v4.x.x. C++ users should use our GitHub release directly instead.
Changes in Python
Python bumped its major version from 5.29.x to 6.30.x.
Dropped Python 3.8 Support
The minimum supported Python version is 3.9. Users should upgrade.
Removed bazel/system_python.bzl Alias
We removed the legacy bazel/system_python.bzl
alias.
Remove direct references to system_python.bzl
in favor of using
protobuf_deps.bzl
instead. Use python/dist/system_python.bzl
where it was
moved
in v5.27.0
if you need a direct reference.
Field Setter Validation Changes
Python’s and upb’s field setters now validate closed enums under edition 2023. Closed enum fields updated with invalid values generate errors.
Removed Deprecated py_proto_library Macro
The deprecated internal py_proto_library
Bazel macro in protobuf.bzl
was
removed. It was replaced by the official py_proto_library
which was moved to
protobuf in bazel/py_proto_library
in v29.x. This implementation was
previously available in rules_python
prior to v29.x.
Remove Deprecated APIs
We removed the following public runtime APIs, which had been marked deprecated for at least one minor or major release.
Reflection Methods
APIs:
reflection.ParseMessage
,
reflection.MakeClass
Replacement: message_factory.GetMessageClass()
RPC Service Interfaces
APIs:
service.RpcException
,
service.Service
,
service.RpcController
,
and
service.RpcChannel
Replacement: Starting with version 2.3.0, RPC implementations should not try to build on these, but should instead provide code generator plugins which generate code specific to the particular RPC implementation.
MessageFactory and SymbolDatabase Methods
APIs:
MessageFactory.GetPrototype
,
MessageFactory.CreatePrototype
,
MessageFactory.GetMessages
,
SymbolDatabase.GetPrototype
,
SymbolDatabase.CreatePrototype
,
and
SymbolDatabase.GetMessages
Replacement: message_factory.GetMessageClass()
and
message_factory.GetMessageClassesForFiles()
.
GetDebugString
APIs:
GetDebugString
Replacement:
No replacement. It’s only in Python C++ which is no longer released. It is not supported in pure Python or UPB.
Python setdefault Behavior Change for Map Fields
setdefault
is similar to dict
for ScalarMap
, except that both key and
value must be set. setdefault
is rejected for MessageMaps
.
Python Nested Message Class __qualname__ Contains the Outer Message Name
Python nested message class __qualname__
now contains the outer message name.
Previously, __qualname__
had the same result with __name__
for nested
message, in that the outer message name was not included.
For example:
message Foo {
message Bar {
bool bool_field = 1;
}
}
nested = test_pb2.Foo.Bar()
self.assertEqual('Bar', nested.__class__.__name__)
self.assertEqual('Foo.Bar', nested.__class__.__qualname__) # It was 'Bar' before
Changes in Objective-C
This is the first breaking release for Objective-C.
Objective-C bumped its major version from 3.x.x to 4.30.x.
Overhauled Unknown Field Handling APIs Deprecating Most of the Existing APIs
We deprecated GPBUnknownFieldSet
and replaced it with GPBUnknownFields
. The
new type preserves the ordering of unknown fields from the original input or API
calls, to ensure any semantic meaning to the ordering is maintained when a
message is written back out.
As part of this, the GPBUnknownField
type also has APIs changes, with almost
all of the existing APIs deprecated and new ones added.
Deprecated property APIs:
varintList
fixed32List
fixed64List
lengthDelimitedList
groupList
Deprecated modification APIs:
addVarint:
addFixed32:
addFixed64:
addLengthDelimited:
addGroup:
Deprecated initializer initWithNumber:
.
New property APIs:
type
varint
fixed32
fixed64
lengthDelimited
group
This type models a single field number in its value, rather than grouping all
the values for a given field number. The APIs for creating new fields are the
add*
APIs on the GPBUnknownFields
class.
We also deprecated -[GPBMessage unknownFields]
. In its place, there are new
APIs to extract and update the unknown fields of the message.
Removed Deprecated APIs
We removed the following public runtime APIs, which had been marked deprecated for at least one minor or major release.
GPBFileDescriptor
API:
-[GPBFileDescriptor
syntax]
Replacement: Obsolete.
GPBMessage mergeFrom:extensionRegistry
API:
-[GPBMessage mergeFrom:extensionRegistry:
]
Replacement:
-[GPBMessage mergeFrom:extensionRegistry:error:
]
GPBDuration timeIntervalSince1970
API:
-[GPBDuration timeIntervalSince1970
]
Replacement:
-[GPBDuration timeInterval
]
GPBTextFormatForUnknownFieldSet
API:
GPBTextFormatForUnknownFieldSet()
Replacement: Obsolete - Use
GPBTextFormatForMessage()
,
which includes any unknown fields.
GPBUnknownFieldSet
API:
GPBUnknownFieldSet
Replacement:
GPBUnknownFields
GPBMessage unknownFields
API:
GPBMessage unknownFields
property
Replacement:
-[GPBUnknownFields initFromMessage:
],
-[GPBMessage mergeUnknownFields:extensionRegistry:error:
],
and
-[GPBMessage clearUnknownFields
]
Removed Deprecated Runtime APIs for Old Gencode
This release removed deprecated runtime methods that supported the Objective-C gencode from before the 3.22.x release. The library also issues a log message at runtime when old generated code is starting up.
API: +[GPBFileDescriptor allocDescriptorForClass:file:fields:fieldCount:storageSize:flags:]
Replacement: Regenerate with a current version of the library.
API: +[GPBFileDescriptor allocDescriptorForClass:rootClass:file:fields:fieldCount:storageSize:flags:]
Replacement: Regenerate with a current version of the library.
API: +[GPBEnumDescriptor allocDescriptorForName:valueNames:values:count:enumVerifier:]
Replacement: Regenerate with a current version of the library.
Replacement: Regenerate with a current version of the library.
API:
-[GPBExtensionDescriptor initWithExtensionDescription:]
Replacement: Regenerate with a current version of the library.
Poison Pill Warnings
We updated poison pills to emit warnings for old gencode + new runtime combinations that work under the new rolling upgrade policy, but will break in the next major bump. For example, Python 4.x.x gencode should work against 5.x.x runtime but warn of upcoming breakage against 6.x.x runtime.
Changes to UTF-8 Enforcement in C# and Ruby
We included a fix to make UTF-8 enforcement consistent across languages. Users with bad non-UTF8 data in string fields may see surfaced UTF-8 enforcement errors earlier.
Ruby and PHP Errors in JSON Parsing
We fixed non-conformance in JSON parsing of strings in numeric fields per the JSON spec.
This fix is not accompanied by a major version bump, but Ruby and PHP now raise
errors for non-numeric strings (such as ""
, "12abc"
, "abc"
) in numeric
fields. v29.x includes a warning for these error cases.
Compiler Changes in v22.0
JSON Field Name Conflicts
Source of changes: PR #11349, PR #10750
We’ve made some subtle changes in how we handle field name conflicts with
respect to JSON mappings. In proto3, we’ve partially loosened the restrictions
and only give errors when field names produce case-sensitive JSON mappings
(camel case of the original name). We now also check the json_name
option, and
give errors for case-sensitive conflicts. In proto2, we’ve tightened
restrictions a bit and will give errors if two json_name
specifications
conflict. If implicit JSON mappings (camel case) have conflicts, we will give
warnings in proto2.
We’ve provided a temporary message/enum option for restoring the legacy
behavior. If renaming the conflicting fields isn’t an option you can take
immediately, set the deprecated_legacy_json_field_conflicts
option on the
specific message/enum. This option will be removed in a future release, but
gives you more time to migrate.
C++ API Changes in v22.0
4.22.0 has breaking changes for C++ runtime and protoc, as announced in August.
Autotools Turndown
Source of changes: PR #10132
In v22.0, we removed all Autotools support from the protobuf compiler and the C++ runtime. If you’re using Autotools to build either of these, you must migrate to CMake or Bazel. We have some dedicated instructions for setting up protobuf with CMake.
Abseil Dependency
Source of changes: PR #10416
With v22.0, we’ve taken on an explicit dependency on Abseil. This allowed us to remove most of our stubs, which were branched from old internal code that later became Abseil. There are a number of subtle behavior changes, but most should be transparent to users. Some notable changes include:
string_view -
absl::string_view
has replacedconst std::string&
in many of our APIs. This is most-commonly used for input arguments, where there should be no noticeable change for users. In a few cases (such as virtual method arguments or return types) users may need to make an explicit change to use the new signature.tables - Instead of STL sets/maps, we now use Abseil’s
flat_hash_map
,flat_hash_set
,btree_map
, andbtree_set
. These are more efficient and allow for heterogeneous lookup. This should be mostly invisible to users, but may cause some subtle behavior changes related to table ordering.logging - Abseil’s logging library is very similar to our old logging code, with just a slightly different spelling (for example,
ABSL_CHECK
instead ofGOOGLE_CHECK
). The biggest difference is that it doesn’t support exceptions, and will now always crash whenFATAL
assertions fail. (Previously we had aPROTOBUF_USE_EXCEPTIONS
flag to switch to exceptions.) Since these only occur when serious issues are encountered, we feel unconditional crashing is a suitable response.Source of logging changes: PR #11623
Build dependency - A new build dependency can always cause breakages for downstream users. We require Abseil LTS 20230125 or later to build.
For Bazel builds, Abseil will be automatically downloaded and built at a pinned LTS release when
protobuf_deps
is run from yourWORKSPACE
. This should be transparent, but if you depend on an older version of Abseil, you’ll need to upgrade your dependency.For CMake builds, we will first look for an existing Abseil installation pulled in by the top-level CMake configuration (see instructions). Otherwise, if
protobuf_ABSL_PROVIDER
is set tomodule
(its default) we will attempt to build and link Abseil from our git submodule. Ifprotobuf_ABSL_PROVIDER
is set topackage
, we will look for a pre-installed system version of Abseil.
Changes in GetCurrentTime Method
On Windows, GetCurrentTime()
is the name of a macro provided by the system.
Prior to v22.x, Protobuf incorrectly removed the macro definition for
GetCurrentTime()
. That made the macro unusable for Windows developers after
including <protobuf/util/time_util.h>
. Starting with v22.x, Protobuf preserves
the macro definition. This may break customer code relying on the previous
behavior, such as if they use the expression
google::protobuf::util::TimeUtil::GetCurrentTime()
.
To migrate your app to the new behavior, change your code to do one of the following:
- if the
GetCurrent
macro is defined, explicitly undefine theGetCurrentTime
macro - prevent the macro expansion by using
(google::protobuf::util::TimeUtil::GetCurrentTime)()
or a similar expression
Example: Undefining the macro
Use this approach if you don’t use the macro from Windows.
Before:
#include <google/protobuf/util/time_util.h>
void F() {
auto time = google::protobuf::util::TimeUtil::GetCurrentTime();
}
After:
#include <google/protobuf/util/time_util.h>
#ifdef GetCurrentTime
#undef GetCurrentTime
#endif
void F() {
auto time = google::protobuf::util::TimeUtil::GetCurrentTime();
}
Example 2: Preventing macro expansion
Before:
#include <google/protobuf/util/time_util.h>
void F() {
auto time = google::protobuf::util::TimeUtil::GetCurrentTime();
}
After:
#include <google/protobuf/util/time_util.h>
void F() {
auto time = (google::protobuf::util::TimeUtil::GetCurrentTime)();
}
C++20 Support
Source of changes: PR #10796
To support C++20, we’ve reserved the new
keywords in C++ generated protobuf
code. As with other reserved keywords, if you use them for any fields, enums, or
messages, we will add an underscore suffix to make them valid C++. For example,
a concept
field will generate a concept_()
getter. In the scenario where you
have existing protos that use these keywords, you’ll need to update the C++ code
that references them to add the appropriate underscores.
Final Classes
Source of changes: PR #11604
As part of a larger effort to harden assumptions made in the Protobuf library,
we’ve marked some classes final
that were never intended to be inherited from.
There are no known use cases for inheriting from these, and doing so would
likely cause problems. There is no mitigation if your code is inheriting from
these classes, but if you think you have some valid reason for the inheritance
you’re using, you can
open an issue.
Container Static Assertions
Source of changes: PR #11550
As part of a larger effort to harden assumptions made in the Protobuf library,
we’ve added static assertions to the Map
, RepeatedField
, and
RepeatedPtrField
containers. These ensure that you’re using these containers
with only expected types, as
covered in our documentation.
If you hit these static assertions, you should migrate your code to use Abseil
or STL containers. std::vector
is a good drop-in replacement for repeated
field containers, and std::unordered_map
or absl::flat_hash_map
for Map
(the former gives similar pointer stability, while the latter is more
efficient).
Cleared Element Deprecation
Source of changes: PR #11588, PR #11639
The RepeatedPtrField
API around “cleared fields” has been deprecated, and will
be fully removed in a later breaking release. This was originally added as an
optimization for reusing elements after they’ve been cleared, but ended up not
working well. If you’re using this API, you should consider migrating to arenas
for better memory reuse.
UnsafeArena Deprecation
Source of changes: PR #10325
As part of a larger effort to remove arena-unsafe APIs, we’ve hidden
RepeatedField::UnsafeArenaSwap
. This is the only one we’ve removed so far, but
in later releases we will continue to remove them and provide helpers to handle
efficient borrowing patterns between arenas. Within a single arena (or the
stack/heap), Swap
is just as efficient as UnsafeArenaSwap
. The benefit is
that it won’t cause invalid memory operations if you accidentally call it across
different arenas.
Map Pair Upgrades
Source of changes: PR #11625
For v22.0 we’ve started cleaning up the Map
API to make it more consistent
with Abseil and STL. Notably, we’ve replaced the MapPair
class with an alias
to std::pair
. This should be transparent for most users, but if you were using
the class directly you may need to update your code.
New JSON Parser
Source of changes: PR #10729
We have rewritten the C++ JSON parser this release. It should be mostly a hidden change, but inevitably some undocumented quirks my have changed; test accordingly. Parsing documents that are not valid RFC-8219 JSON (such as those that are missing quotes or using non-standard bools) is deprecated and will be removed in a future release. The serialization order of fields is now guaranteed to match the field number order, where before it was less deterministic.
As part of this migration, all of the files under util/internal have been deleted. These were used in the old parser, and were never intended to be used externally.
Arena::Init
Source of changes: PR #10623
The Init
method in Arena
was code that didn’t do anything, and has now been
removed. If you were calling this method, you likely meant to call the Arena
constructor directly with a set of ArenaOptions
. You should either delete the
call or migrate to that constructor.
ErrorCollector Migration
Source of changes: PR #11555
As part of our Abseil migration, we’re moving from const std::string&
to
absl::string_view
. For our three error collector classes, this can’t be done
without breaking existing code. For v22.0, we’ve decided to release both
variants, and rename the methods from AddError
and AddWarning
to
RecordError
and RecordWarning
. The old signature has been marked deprecated,
and will be slightly less efficient (due to string copies), but will otherwise
still work. You should migrate these to the new version, as the Add*
methods
will be removed in a later breaking release.