gcpug
zagane
Go

zagane is a static analysis tool which can find bugs in spanner's code

Last updated Jun 1, 2026
99
Stars
16
Forks
12
Issues
0
Stars/day
Attention Score
28
Language breakdown
Go 100.0%
Files click to expand
README

zagane

GoDoc

zagane is a static analysis tool which can find bugs in spanner's code. zagane consists of several analyzers.

  • unstopiter: it finds iterators which did not stop.
  • unclosetx: it finds transactions which does not close
wraperr: it finds (spanner.Client).ReadWriteTransaction calls which returns wrapped errors

Install

You can get zagane by go install command.

$ go install github.com/gcpug/zagane@latest

How to use

zagane run with go vet as below.

$ go vet -vettool=$(which zagane) github.com/gcpug/spshovel/...

github.com/gcpug/spshovel/spanner

spanner/spanner_service.go:29:29: iterator must be stop

Analyzers

unstopiter

unstopiter finds spanner.RowIterator which is not calling Stop method or Do method such as below code.

iter := client.Single().Query(ctx, stmt)
for {
	row, err := iter.Next()
	// ...
}

This code must be fixed as below.

iter := client.Single().Query(ctx, stmt)
defer iter.Stop()
for {
	row, err := iter.Next()
	// ...
}

unclosetx

unclosetx finds spanner.ReadOnlyTransaction which is not calling Close method such as below code.

tx := client.ReadOnlyTransaction()
// ...

This code must be fixed as below.

tx := client.ReadOnlyTransaction()
defer tx.Close()
// ...

When a transaction is created by (*spanner.Client).Single, unclosetx ignore it.

wraperr

wraperr finds ReadWriteTransaction calls which returns wrapped errors such as the below code.

func f(ctx context.Context, client *spanner.Client) {
	client.ReadWriteTransaction(ctx, func(ctx context.Context, txn *spanner.ReadWriteTransaction) error {
		stmt := spanner.Statement{SQL: SELECT 1}
		_, err := client.Single().Query(ctx, stmt).Next()
		if err != nil {
			return errors.Wrap(err, "wrapped") // want "must not be wrapped"
		}
		return nil
	})
}

This code must be fixed as below.

func f(ctx context.Context, client *spanner.Client) {
	client.ReadWriteTransaction(ctx, func(ctx context.Context, txn *spanner.ReadWriteTransaction) error {
		stmt := spanner.Statement{SQL: SELECT 1}
		_, err := client.Single().Query(ctx, stmt).Next()
		if err != nil {
			return err
		}
		return nil
	})
}

Ignore Checks

Analyzers ignore nodes which are annotated by staticcheck's style comments as belows. A ignore comment includes analyzer names and reason of ignoring checking. If you specify zagane as analyzer name, all analyzers ignore corresponding code.

//lint:ignore zagane reason
var n int

//lint:ignore unstopiter reason , = client.Single().Query(ctx, stmt).Next()

Analyze with golang.org/x/tools/go/analysis

You can get analyzers of zagane from zagane.Analyzers. And you can use them with unitchecker.

Why name is "zagane"?

"zagane" (座金) means "washer" in Japanese. A washer works between a spanner and other parts. zagane also works between Cloud Spanner and your applications.

🔗 More in this category

© 2026 GitRepoTrend · gcpug/zagane · Updated daily from GitHub