Repository: bufbuild/buf (Go)

Issue:
Empty file causes buf generate failure
In my buf module, I have a file `acme/v1/stub.proto`:

```
syntax = "proto3";

package acme.v1;

import "google/rpc/code.proto";
import "google/rpc/error_details.proto";
import "google/rpc/status.proto";
``` 

Buf cli will crash on it with `Failure: missing "acme/v1/stub.proto"`. I'm assuming this is because there are no types in there.


Discussion:
Using `buf` version `v1.53.0`, I created a module with the file contents you have above:

```
$ tree .
.
├── buf.gen.yaml
├── buf.lock
├── buf.yaml
└── proto
    └── stub.proto

$ cat proto/stub.proto
syntax = "proto3";

package acme.v1;

import "google/rpc/code.proto";
import "google/rpc/error_details.proto";
import "google/rpc/status.proto";
```

My `buf.yaml` and `buf.gen.yaml`:

```
$ cat buf.yaml
version: v2
deps:
  - buf.build/googleapis/googleapis

$ cat buf.gen.yaml
version: v2
managed:
  enabled: true
  override:
    - file_option: go_package_prefix
      value: company.com/foo/bar
plugins:
  - remote: buf.build/protocolbuffers/go
    out: gen/
```

`buf generate` succeeds with generated code for me. Could you provide a repro for the issue that you are seeing?



Hm, both nix and brew have only 1.52.1.
Thank you, I’ll upgrade and verify.
@doriable I found the reason. It happens if a gen spec has `exclude_types`:

```
plugins:
  - remote: buf.build/protocolbuffers/go
    out: gen/
    exclude_types:
      - buf.validate
      - google.api.field_behavior
      - google.api.http
      - gnostic.openapi.v3
```
Thank you for this context, I was able to make a repro. We have a direction for the root cause, so we'll be working on a fix for this. I'll update the issue once a fix has been merged and available for the next release!



Patch:
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 906106bb3e..ac21337368 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -5,6 +5,7 @@
 - Add `CSR` category to breaking rules.
 - Add support for local bufplugins for `protoc-gen-buf-breaking` and `protoc-gen-buf-lint`.
 - Add RISC-V (64-bit) binaries for Linux to releases.
+- Fix type filtering on `buf generate` for empty files, files with no declared types.
 
 ## [v1.53.0] - 2025-04-21
 
diff --git a/private/bufpkg/bufimage/bufimageutil/bufimageutil.go b/private/bufpkg/bufimage/bufimageutil/bufimageutil.go
index e77f0c5c0a..6a264ee513 100644
--- a/private/bufpkg/bufimage/bufimageutil/bufimageutil.go
+++ b/private/bufpkg/bufimage/bufimageutil/bufimageutil.go
@@ -450,10 +450,9 @@ func (t *transitiveClosure) addElement(
 
 	switch typedDescriptor := descriptor.(type) {
 	case *descriptorpb.FileDescriptorProto:
-		typeNames, ok := imageIndex.FileTypes[typedDescriptor.GetName()]
-		if !ok {
-			return fmt.Errorf("missing %q", typedDescriptor.GetName())
-		}
+		// If the file we are attempting to include is empty (has no types defined), it is still
+		// valid for inclusion.
+		typeNames := imageIndex.FileTypes[typedDescriptor.GetName()]
 		// A file includes all elements. The types are resolved in the image index
 		// to ensure all nested types are included.
 		for _, typeName := range typeNames {


Test patch:
diff --git a/private/bufpkg/bufimage/bufimageutil/bufimageutil_test.go b/private/bufpkg/bufimage/bufimageutil/bufimageutil_test.go
index c3791cd6bf..30032118eb 100644
--- a/private/bufpkg/bufimage/bufimageutil/bufimageutil_test.go
+++ b/private/bufpkg/bufimage/bufimageutil/bufimageutil_test.go
@@ -504,6 +504,18 @@ func TestDependencies(t *testing.T) {
 	})
 }
 
+func TestEmptyFiles(t *testing.T) {
+	t.Parallel()
+	t.Run("include_empty_file", func(t *testing.T) {
+		t.Parallel()
+		runDiffTest(t, "testdata/empty", "empty.include.txtar", WithIncludeTypes("include"))
+	})
+	t.Run("exclude_empty_file", func(t *testing.T) {
+		t.Parallel()
+		runDiffTest(t, "testdata/empty", "empty.exclude.txtar", WithExcludeTypes("include"))
+	})
+}
+
 func getImage(ctx context.Context, logger *slog.Logger, testdataDir string, options ...bufimage.BuildImageOption) (storage.ReadWriteBucket, bufimage.Image, error) {
 	bucket, err := storageos.NewProvider().NewReadWriteBucket(testdataDir)
 	if err != nil {
diff --git a/private/bufpkg/bufimage/bufimageutil/testdata/empty/a.proto b/private/bufpkg/bufimage/bufimageutil/testdata/empty/a.proto
new file mode 100644
index 0000000000..eb5e565bf6
--- /dev/null
+++ b/private/bufpkg/bufimage/bufimageutil/testdata/empty/a.proto
@@ -0,0 +1,2 @@
+syntax = "proto3";
+package include;
diff --git a/private/bufpkg/bufimage/bufimageutil/testdata/empty/b.proto b/private/bufpkg/bufimage/bufimageutil/testdata/empty/b.proto
new file mode 100644
index 0000000000..5eda7c09c2
--- /dev/null
+++ b/private/bufpkg/bufimage/bufimageutil/testdata/empty/b.proto
@@ -0,0 +1,3 @@
+syntax = "proto3";
+
+import "a.proto";
diff --git a/private/bufpkg/bufimage/bufimageutil/testdata/empty/c.proto b/private/bufpkg/bufimage/bufimageutil/testdata/empty/c.proto
new file mode 100644
index 0000000000..44a35b8934
--- /dev/null
+++ b/private/bufpkg/bufimage/bufimageutil/testdata/empty/c.proto
@@ -0,0 +1,8 @@
+syntax = "proto3";
+package pkg;
+
+import "a.proto";
+
+message Foo {
+  string name = 1;
+}
diff --git a/private/bufpkg/bufimage/bufimageutil/testdata/empty/d.proto b/private/bufpkg/bufimage/bufimageutil/testdata/empty/d.proto
new file mode 100644
index 0000000000..942294602a
--- /dev/null
+++ b/private/bufpkg/bufimage/bufimageutil/testdata/empty/d.proto
@@ -0,0 +1,4 @@
+syntax = "proto3";
+package pkg;
+
+import "google/protobuf/any.proto";
diff --git a/private/bufpkg/bufimage/bufimageutil/testdata/empty/empty.exclude.txtar b/private/bufpkg/bufimage/bufimageutil/testdata/empty/empty.exclude.txtar
new file mode 100644
index 0000000000..50bdce55b3
--- /dev/null
+++ b/private/bufpkg/bufimage/bufimageutil/testdata/empty/empty.exclude.txtar
@@ -0,0 +1,11 @@
+-- b.proto --
+syntax = "proto3";
+-- c.proto --
+syntax = "proto3";
+package pkg;
+message Foo {
+  string name = 1;
+}
+-- d.proto --
+syntax = "proto3";
+package pkg;
diff --git a/private/bufpkg/bufimage/bufimageutil/testdata/empty/empty.include.txtar b/private/bufpkg/bufimage/bufimageutil/testdata/empty/empty.include.txtar
new file mode 100644
index 0000000000..1ac882db49
--- /dev/null
+++ b/private/bufpkg/bufimage/bufimageutil/testdata/empty/empty.include.txtar
@@ -0,0 +1,3 @@
+-- a.proto --
+syntax = "proto3";
+package include;