{"record":{"id":"d09efeeee199bf09","repo":"vitessio/vitess","slug":"snapshottime-is-required-for-snapshot-keyspaces","errorCode":null,"errorMessage":"SnapshotTime is required for SNAPSHOT keyspaces","messagePattern":"SnapshotTime is required for SNAPSHOT keyspaces","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"go/vt/vtctl/grpcvtctldserver/server.go","lineNumber":938,"sourceCode":"\n\tdefer panicHandler(&err)\n\n\tspan.Annotate(\"keyspace\", req.Name)\n\tspan.Annotate(\"keyspace_type\", topoproto.KeyspaceTypeLString(req.Type))\n\tspan.Annotate(\"force\", req.Force)\n\tspan.Annotate(\"allow_empty_vschema\", req.AllowEmptyVSchema)\n\tspan.Annotate(\"durability_policy\", req.DurabilityPolicy)\n\n\tswitch req.Type {\n\tcase topodatapb.KeyspaceType_NORMAL:\n\tcase topodatapb.KeyspaceType_SNAPSHOT:\n\t\tif req.BaseKeyspace == \"\" {\n\t\t\terr = errors.New(\"BaseKeyspace is required for SNAPSHOT keyspaces\")\n\t\t\treturn nil, err\n\t\t}\n\n\t\tif req.SnapshotTime == nil {\n\t\t\terr = errors.New(\"SnapshotTime is required for SNAPSHOT keyspaces\")\n\t\t\treturn nil, err\n\t\t}\n\n\t\tspan.Annotate(\"base_keyspace\", req.BaseKeyspace)\n\t\tspan.Annotate(\"snapshot_time\", protoutil.TimeFromProto(req.SnapshotTime).String())\n\tdefault:\n\t\treturn nil, fmt.Errorf(\"unknown keyspace type %v\", req.Type)\n\t}\n\n\tki := &topodatapb.Keyspace{\n\t\tKeyspaceType:     req.Type,\n\t\tBaseKeyspace:     req.BaseKeyspace,\n\t\tSnapshotTime:     req.SnapshotTime,\n\t\tDurabilityPolicy: req.DurabilityPolicy,\n\t\tSidecarDbName:    req.SidecarDbName,\n\t}\n\n\terr = s.ts.CreateKeyspace(ctx, req.Name, ki)","sourceCodeStart":920,"sourceCodeEnd":956,"githubUrl":"https://github.com/vitessio/vitess/blob/01a25a7d176f94613b8d59d799f438380a8760e4/go/vt/vtctl/grpcvtctldserver/server.go#L920-L956","documentation":"CreateKeyspace requires SNAPSHOT keyspaces to carry an explicit SnapshotTime, the point-in-time of the source keyspace the snapshot represents. Without it the snapshot has no defined temporal anchor, so the RPC rejects the request before creating any topology records.","triggerScenarios":"Calling CreateKeyspace with req.Type = topodatapb.KeyspaceType_SNAPSHOT and req.SnapshotTime == nil (CLI: --type=SNAPSHOT without a snapshot timestamp).","commonSituations":"Scripts that set BaseKeyspace but forget the timestamp; recovery/DR tooling reconstructing snapshot keyspaces from incomplete metadata; hand-written protobuf requests in tests.","solutions":["Supply --snapshot-time (RFC3339) on the CLI or set req.SnapshotTime to a valid timestamp proto","Ensure BaseKeyspace is also set, since it is validated just before SnapshotTime","Use the source keyspace's recorded creation/snapshot timestamp if unknown"],"exampleFix":"// before\nreq := &vtctldatapb.CreateKeyspaceRequest{Type: topodatapb.KeyspaceType_SNAPSHOT, BaseKeyspace: \"commerce\"}\n// after\nreq := &vtctldatapb.CreateKeyspaceRequest{\n  Type: topodatapb.KeyspaceType_SNAPSHOT,\n  BaseKeyspace: \"commerce\",\n  SnapshotTime: timestamppb.New(time.Unix(1700000000, 0)),\n}","handlingStrategy":"validation","validationCode":"if req.GetType() == topodatapb.KeyspaceType_SNAPSHOT && req.GetSnapshotTime() == nil {\n    return fmt.Errorf(\"SnapshotTime must be set for SNAPSHOT keyspace %s\", req.Name)\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Record the snapshot timestamp at capture time and carry it in your provisioning metadata","Validate the full SNAPSHOT field set (Type, BaseKeyspace, SnapshotTime) in one pre-submit check","Use RFC3339 timestamps to avoid parsing surprises downstream"],"tags":["vtctld","keyspace","validation","snapshot"],"backgroundTag":"missing-required-argument","analyzedSha":"01a25a7d176f94613b8d59d799f438380a8760e4","analyzedAt":"2026-09-01T17:28:30.605Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}