{"record":{"id":"18387d7ce4c20503","repo":"vitessio/vitess","slug":"failed-to-parse-options-column-v","errorCode":null,"errorMessage":"failed to parse options column: %v","messagePattern":"failed to parse options column: (.+?)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"go/vt/binlog/binlogplayer/binlog_player.go","lineNumber":616,"sourceCode":"\tif err != nil {\n\t\treturn VRSettings{}, fmt.Errorf(\"failed to parse stop_pos column: %v\", err)\n\t}\n\tworkflowType, err := vrRow.ToInt32(\"workflow_type\")\n\tif err != nil {\n\t\treturn VRSettings{}, fmt.Errorf(\"failed to parse workflow_type column: %v\", err)\n\t}\n\tworkflowSubType, err := vrRow.ToInt32(\"workflow_sub_type\")\n\tif err != nil {\n\t\treturn VRSettings{}, fmt.Errorf(\"failed to parse workflow_sub_type column: %v\", err)\n\t}\n\tdeferSecondaryKeys, err := vrRow.ToBool(\"defer_secondary_keys\")\n\tif err != nil {\n\t\treturn VRSettings{}, fmt.Errorf(\"failed to parse defer_secondary_keys column: %v\", err)\n\t}\n\toptions := vrRow.AsString(\"options\", \"{}\")\n\tvar workflowOptions vtctldata.WorkflowOptions\n\tif err := json.Unmarshal([]byte(options), &workflowOptions); err != nil {\n\t\treturn VRSettings{}, fmt.Errorf(\"failed to parse options column: %v\", err)\n\t}\n\treturn VRSettings{\n\t\tStartPos:           startPos,\n\t\tStopPos:            stopPos,\n\t\tMaxTPS:             maxTPS,\n\t\tMaxReplicationLag:  maxReplicationLag,\n\t\tState:              binlogdatapb.VReplicationWorkflowState(binlogdatapb.VReplicationWorkflowState_value[vrRow.AsString(\"state\", \"\")]),\n\t\tWorkflowType:       binlogdatapb.VReplicationWorkflowType(workflowType),\n\t\tWorkflowName:       vrRow.AsString(\"workflow\", \"\"),\n\t\tWorkflowSubType:    binlogdatapb.VReplicationWorkflowSubType(workflowSubType),\n\t\tDeferSecondaryKeys: deferSecondaryKeys,\n\t\tWorkflowOptions:    &workflowOptions,\n\t}, nil\n}\n\n// CreateVReplication returns a statement to populate the first value into\n// the _vt.vreplication table.\nfunc CreateVReplication(workflow string, source *binlogdatapb.BinlogSource, position string, maxTPS, maxReplicationLag, timeUpdated int64, dbName string,","sourceCodeStart":598,"sourceCodeEnd":634,"githubUrl":"https://github.com/vitessio/vitess/blob/01a25a7d176f94613b8d59d799f438380a8760e4/go/vt/binlog/binlogplayer/binlog_player.go#L598-L634","documentation":"The options column stores a JSON blob of WorkflowOptions for the stream. json.Unmarshal of its contents failed, meaning the column does not hold valid JSON. The default is \"{}\" when the SQL value is empty, so this error implies actual corrupt/non-JSON content.","triggerScenarios":"json.Unmarshal([]byte(options)) fails: options contains truncated JSON, plain text, single-quoted pseudo-JSON from manual edits, or binary garbage written by an external tool.","commonSituations":"Manual edits to _vt.vreplication writing unquoted/invalid JSON; interrupted writes; migration scripts rewriting the column without escaping.","solutions":["Inspect: `select uid, options from _vt.vreplication where uid=<id>` and validate the text is well-formed JSON.","Reset to a valid empty object: `update _vt.vreplication set options='{}' where uid=<id>` if options are not essential, or re-enter the correct JSON (properly quoted via VExec to avoid shell escaping issues).","If options carry required workflow state (e.g. source/ target keyspaces), re-create the workflow rather than hand-crafting the JSON.","Find and stop any external tool writing to the column."],"exampleFix":"// before: invalid JSON (unquoted keys)\nupdate _vt.vreplication set options='{source: \"ks\"}' where uid=1;\n// after: valid JSON, or reset to empty\nupdate _vt.vreplication set options='{}' where uid=1;","handlingStrategy":"validation","validationCode":"qr, _ := dbClient.ExecuteFetch(fmt.Sprintf(\"SELECT options FROM _vt.vreplication WHERE uid=%d\", uid), 1)\nif len(qr.Rows) == 1 {\n\topts := qr.Named().Row().AsString(\"options\", \"\")\n\tvar wo vtctldatapb.WorkflowOptions\n\tif err := json.Unmarshal([]byte(opts), &wo); err != nil {\n\t\treturn fmt.Errorf(\"options %q is not valid JSON; reset to '{}' or re-create the workflow\", opts)\n\t}\n}","typeGuard":"func isValidWorkflowOptionsJSON(s string) bool {\n\tvar wo vtctldatapb.WorkflowOptions\n\treturn json.Unmarshal([]byte(s), &wo) == nil\n}","tryCatchPattern":"settings, err := binlogplayer.ReadVRSettings(dbClient, uid)\nif err != nil && strings.Contains(err.Error(), \"failed to parse options\") {\n\t// reset to empty options and retry once\n\t_, _ = dbClient.ExecuteFetch(fmt.Sprintf(\"UPDATE _vt.vreplication SET options='{}' WHERE uid=%d\", uid), 0)\n\tsettings, err = binlogplayer.ReadVRSettings(dbClient, uid)\n}","preventionTips":["Write the options column only via the workflow API.","When editing JSON manually, validate it (e.g. jq) before committing.","Prefer resetting to '{}' over hand-crafting complex options.","Quote JSON through VExec parameters to avoid shell escaping bugs."],"tags":["vreplication","json","parsing","data-corruption"],"backgroundTag":"invalid-json","analyzedSha":"01a25a7d176f94613b8d59d799f438380a8760e4","analyzedAt":"2026-09-01T17:28:30.605Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}