{"record":{"id":"356804546529e369","repo":"bytebase/bytebase","slug":"failed-to-unmarshal-query-data-policy-payload","errorCode":null,"errorMessage":"failed to unmarshal query data policy payload","messagePattern":"failed to unmarshal query data policy payload","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"backend/api/v1/org_policy_service_converter.go","lineNumber":169,"sourceCode":"\tif err := common.ProtojsonUnmarshaler.Unmarshal([]byte(payloadStr), p); err != nil {\n\t\treturn nil, errors.Wrapf(err, \"failed to unmarshal rollout policy payload\")\n\t}\n\treturn &v1pb.Policy_RolloutPolicy{\n\t\tRolloutPolicy: p,\n\t}, nil\n}\n\nfunc convertToStorePBRolloutPolicy(policy *v1pb.RolloutPolicy) *storepb.RolloutPolicy {\n\treturn &storepb.RolloutPolicy{\n\t\tAutomatic: policy.Automatic,\n\t\tRoles:     policy.Roles,\n\t}\n}\n\nfunc convertToV1PBQueryDataPolicy(payloadStr string) (*v1pb.Policy_QueryDataPolicy, error) {\n\tpayload := &storepb.QueryDataPolicy{}\n\tif err := common.ProtojsonUnmarshaler.Unmarshal([]byte(payloadStr), payload); err != nil {\n\t\treturn nil, errors.Wrapf(err, \"failed to unmarshal query data policy payload\")\n\t}\n\treturn &v1pb.Policy_QueryDataPolicy{\n\t\tQueryDataPolicy: &v1pb.QueryDataPolicy{\n\t\t\tDisableExport:        payload.DisableExport,\n\t\t\tMaximumResultRows:    payload.MaximumResultRows,\n\t\t\tDisableCopyData:      payload.DisableCopyData,\n\t\t\tAllowAdminDataSource: payload.AllowAdminDataSource,\n\t\t},\n\t}, nil\n}\n\nfunc convertToQueryDataPolicyPayload(policy *v1pb.QueryDataPolicy) *storepb.QueryDataPolicy {\n\treturn &storepb.QueryDataPolicy{\n\t\tDisableExport:        policy.DisableExport,\n\t\tMaximumResultRows:    policy.MaximumResultRows,\n\t\tDisableCopyData:      policy.DisableCopyData,\n\t\tAllowAdminDataSource: policy.AllowAdminDataSource,\n\t}","sourceCodeStart":151,"sourceCodeEnd":187,"githubUrl":"https://github.com/bytebase/bytebase/blob/1870550677fe08f0d2a78c07acd27541464eb945/backend/api/v1/org_policy_service_converter.go#L151-L187","documentation":"convertToV1PBQueryDataPolicy parses the stored JSON payload of a query-data policy into storepb.QueryDataPolicy via a strict protojson unmarshaler. On failure it wraps the error as 'failed to unmarshal query data policy payload'. Like the rollout variant, this signals a persisted payload that no longer matches the proto schema.","triggerScenarios":"GetPolicy/ListPolicies on a QUERY_DATA policy whose payload JSON is malformed, has unknown/wrong-typed fields, or uses keys not accepted by protojson (e.g. snake_case like disable_export instead of disableExport).","commonSituations":"Hand-edited database rows, payloads produced by external tooling with encoding/json, schema drift after version upgrades that changed QueryDataPolicy fields (e.g. addition of disableCopyData), or truncated JSON in the payload column.","solutions":["Fix the stored payload JSON to match storepb.QueryDataPolicy with camelCase protojson keys.","Reset the policy row (delete it) and recreate it via the API so the server writes a valid payload.","Verify you are running the version that owns the current QueryDataPolicy schema; upgrade/downgrade as needed.","Re-save the policy through UpdatePolicy to re-serialize it with protojson."],"exampleFix":"// before (snake_case, plain JSON)\n{\"disable_export\": true, \"maximum_result_rows\": 100}\n// after (protojson)\n{\"disableExport\": true, \"maximumResultRows\": 100}","handlingStrategy":"validation","validationCode":"// Pre-validate that the payload unmarshals as QueryDataPolicy\np := &storepb.QueryDataPolicy{}\nif err := common.ProtojsonUnmarshaler.Unmarshal([]byte(payloadStr), p); err != nil {\n    return fmt.Errorf(\"query data policy payload invalid: %w\", err)\n}","typeGuard":null,"tryCatchPattern":"policy, err := svc.GetPolicy(ctx, req)\nif err != nil {\n    if strings.Contains(err.Error(), \"failed to unmarshal query data policy payload\") {\n        // reset the row and recreate the policy via UpdatePolicy\n    }\n    return err\n}","preventionTips":["Serialize QueryDataPolicy payloads exclusively with protojson (camelCase keys)","Avoid writing policy payloads with encoding/json or external tools","After version upgrades, re-save policies if QueryDataPolicy fields changed","Monitor for truncated payload JSON in the policy table"],"tags":["protobuf","policy","unmarshal"],"backgroundTag":"protobuf-unmarshal-failed","analyzedSha":"1870550677fe08f0d2a78c07acd27541464eb945","analyzedAt":"2026-09-06T21:16:13.665Z","contentChangedAt":"2026-09-06T21:16:13.665Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}