{"record":{"id":"28e786929c5bd07d","repo":"grpc/grpc-go","slug":"error-parsing-custom-audit-logger-config-v","errorCode":null,"errorMessage":"error parsing custom audit logger config: %v","messagePattern":"error parsing custom audit logger config: (.+?)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"authz/rbac_translator.go","lineNumber":318,"sourceCode":"\t\t}\n\t\tallow.AuditCondition = v3rbacpb.RBAC_AuditLoggingOptions_AuditCondition(rbacCondition)\n\t\tdeny.AuditCondition = toDenyCondition(v3rbacpb.RBAC_AuditLoggingOptions_AuditCondition(rbacCondition))\n\t}\n\n\tfor i, config := range options.AuditLoggers {\n\t\tif config.Name == \"\" {\n\t\t\treturn nil, nil, fmt.Errorf(\"missing required field: name in audit_logging_options.audit_loggers[%v]\", i)\n\t\t}\n\t\tif config.Config == nil {\n\t\t\tconfig.Config = &structpb.Struct{}\n\t\t}\n\t\ttypedStruct := &v1xdsudpatypepb.TypedStruct{\n\t\t\tTypeUrl: typeURLPrefix + config.Name,\n\t\t\tValue:   config.Config,\n\t\t}\n\t\tcustomConfig, err := anypb.New(typedStruct)\n\t\tif err != nil {\n\t\t\treturn nil, nil, fmt.Errorf(\"error parsing custom audit logger config: %v\", err)\n\t\t}\n\n\t\tlogger := &v3corepb.TypedExtensionConfig{Name: config.Name, TypedConfig: customConfig}\n\t\trbacConfig := v3rbacpb.RBAC_AuditLoggingOptions_AuditLoggerConfig{\n\t\t\tIsOptional:  config.IsOptional,\n\t\t\tAuditLogger: logger,\n\t\t}\n\t\tallow.LoggerConfigs = append(allow.LoggerConfigs, &rbacConfig)\n\t\tdeny.LoggerConfigs = append(deny.LoggerConfigs, &rbacConfig)\n\t}\n\n\treturn allow, deny, nil\n}\n\n// Maps the AuditCondition coming from AuditLoggingOptions to the proper\n// condition for the deny policy RBAC proto\nfunc toDenyCondition(condition v3rbacpb.RBAC_AuditLoggingOptions_AuditCondition) v3rbacpb.RBAC_AuditLoggingOptions_AuditCondition {\n\t// Mapping the overall policy AuditCondition to what it must be for the Deny and Allow RBAC","sourceCodeStart":300,"sourceCodeEnd":336,"githubUrl":"https://github.com/grpc/grpc-go/blob/03255a9237b6eb32710f6bc4f2de9a675b99fe36/authz/rbac_translator.go#L300-L336","documentation":"Raised by toProtos when anypb.New(typedStruct) fails while wrapping a custom audit logger's Config struct into a google.protobuf.Any. This is a protobuf marshalling failure on the user-supplied Struct — almost always caused by a malformed structpb.Struct (e.g. a null/invalid Value, a nil map where a struct is required) rather than by the name field.","triggerScenarios":"An audit_loggers[].config value that, after being decoded into a structpb.Struct, cannot be serialized into a TypedStruct Any. anypb.New returns a non-nil error and the translator wraps it.","commonSituations":"Hand-crafting the logger config as raw JSON with illegal protobuf-struct values (e.g. a number where a struct is expected, deeply nested nulls); a serialization edge case when Config is left as a zero-valued struct in older protobuf versions; type mismatch between what the logger expects and what is supplied.","solutions":["Inspect the inner %v — anypb.New errors usually name the offending field or type.","Replace the custom config with a minimal valid structpb (e.g. empty {}) to confirm the logger loads, then add fields back one at a time.","Generate the config from a real structpb.Struct in Go rather than hand-writing JSON, to guarantee valid Value types.","Check the logger extension's documented config schema for required nested types."],"exampleFix":"// before: config has an illegal null-in-struct value\n\"config\": { \"fields\": { \"sink\": { \"nullValue\": null } } }\n\n// after:\n\"config\": { \"fields\": { \"sink\": { \"stringValue\": \"stderr\" } } }","handlingStrategy":"validation","validationCode":"// Confirm the logger config is a valid structpb.Struct before the SDK\n// tries to wrap it in an Any.\nfunc validateLoggerConfigs(policyStr string) error {\n    var p struct {\n        AuditLoggingOptions struct {\n            AuditLoggers []struct {\n                Config *structpb.Struct `json:\"config\"`\n            } `json:\"audit_loggers\"`\n        } `json:\"audit_logging_options\"`\n    }\n    if err := json.Unmarshal([]byte(policyStr), &p); err != nil { return err }\n    for i, l := range p.AuditLoggingOptions.AuditLoggers {\n        if l.Config == nil { continue }\n        // round-trip through proto marshalling to mimic anypb.New\n        if _, err := anypb.New(&v1xdsudpatypepb.TypedStruct{Value: l.Config}); err != nil {\n            return fmt.Errorf(\"audit_loggers[%d]: invalid config: %v\", i, err)\n        }\n    }\n    return nil\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Build logger configs from real Go structs, not hand-written JSON.","Avoid null/Value mismatches in nested fields.","Test minimal config first, add fields incrementally.","Cross-check against the logger extension's documented schema."],"tags":["authz","rbac","audit-logging","protobuf","config"],"analyzedSha":"03255a9237b6eb32710f6bc4f2de9a675b99fe36","analyzedAt":"2026-08-07T00:29:34.215Z","schemaVersion":2},"datasetVersion":"2026-08-07T03:17:09.362Z"}