{"record":{"id":"89ee5cab08d230d5","repo":"vitessio/vitess","slug":"w-unable-to-parse-json-of-load-flags","errorCode":null,"errorMessage":"%w: unable to parse JSON of load flags","messagePattern":"%w: unable to parse JSON of load flags","errorType":"error_code","errorClass":"ErrMySQLShellPreCheck","httpStatus":null,"severity":"error","filePath":"go/vt/mysqlctl/mysqlshellbackupengine.go","lineNumber":507,"sourceCode":"\tif !isObjectStoreFlags(mysqlShellDumpFlags) {\n\t\terr := os.MkdirAll(location, 0o750)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"failure creating directory %s: %w\", location, err)\n\t\t}\n\t}\n\n\treturn nil\n}\n\nfunc (be *MySQLShellBackupEngine) restorePreCheck(ctx context.Context, params RestoreParams) (shouldDeleteUsers bool, err error) {\n\tif mysqlShellFlags == \"\" {\n\t\treturn shouldDeleteUsers, fmt.Errorf(\"%w: at least the --js flag is required in the value of the flag --mysql-shell-flags\", ErrMySQLShellPreCheck)\n\t}\n\n\tloadFlags := map[string]any{}\n\terr = json.Unmarshal([]byte(mysqlShellLoadFlags), &loadFlags)\n\tif err != nil {\n\t\treturn false, fmt.Errorf(\"%w: unable to parse JSON of load flags\", ErrMySQLShellPreCheck)\n\t}\n\n\tif val, ok := loadFlags[\"updateGtidSet\"]; !ok || val != \"replace\" {\n\t\treturn false, fmt.Errorf(\"%w: mysql-shell needs to restore with updateGtidSet set to \\\"replace\\\" to work with Vitess\", ErrMySQLShellPreCheck)\n\t}\n\n\tif val, ok := loadFlags[\"progressFile\"]; !ok || val != \"\" {\n\t\treturn false, fmt.Errorf(\"%w: \\\"progressFile\\\" needs to be empty as vitess always starts a restore from scratch\", ErrMySQLShellPreCheck)\n\t}\n\n\tif val, ok := loadFlags[\"skipBinlog\"]; !ok || val != true {\n\t\treturn false, fmt.Errorf(\"%w: \\\"skipBinlog\\\" needs to set to true\", ErrMySQLShellPreCheck)\n\t}\n\n\tif val, ok := loadFlags[\"loadUsers\"]; ok && val == true {\n\t\tshouldDeleteUsers = true\n\t}\n","sourceCodeStart":489,"sourceCodeEnd":525,"githubUrl":"https://github.com/vitessio/vitess/blob/01a25a7d176f94613b8d59d799f438380a8760e4/go/vt/mysqlctl/mysqlshellbackupengine.go#L489-L525","documentation":"The mysql-shell load flags (--mysql-shell-load-flags) must be valid JSON because restorePreCheck() unmarshals them into a map. If json.Unmarshal fails, this error wrapping ErrMySQLShellPreCheck is returned and the restore is aborted.","triggerScenarios":"ExecuteRestore -> restorePreCheck when --mysql-shell-load-flags contains malformed JSON: single quotes instead of double, trailing commas, unquoted keys, or shell-mangled quoting stripping double quotes.","commonSituations":"Flags passed through systemd units, Helm charts, or shell scripts where double quotes need escaping and get consumed by an intermediate shell layer; hand-edited config introducing a trailing comma.","solutions":["Validate the flag value with `jq . <<< '<value>'` or json.Unmarshal in a scratch program; fix the JSON syntax.","Escape double quotes properly for the launch layer (systemd Environment=, Helm values, etc.).","Use a minimal correct value first: '{\"updateGtidSet\":\"replace\",\"progressFile\":\"\"}' and add keys incrementally."],"exampleFix":"// before: invalid JSON (single quotes)\n--mysql-shell-load-flags \"{'updateGtidSet':'replace'}\"\n// after\n--mysql-shell-load-flags \"{\\\"updateGtidSet\\\":\\\"replace\\\",\\\"progressFile\\\":\\\"\\\"}\"","handlingStrategy":"validation","validationCode":"probe := map[string]any{}\nif err := json.Unmarshal([]byte(mysqlShellLoadFlags), &probe); err != nil {\n\treturn fmt.Errorf(\"--mysql-shell-load-flags is not valid JSON: %v\", err)\n}","typeGuard":null,"tryCatchPattern":"err := engine.ExecuteRestore(ctx, restoreParams)\nif errors.Is(err, mysqlctl.ErrMySQLShellLoadFlagsNotParseable) || strings.Contains(err.Error(), \"unable to parse JSON of load flags\") {\n\t// fix JSON quoting in the launch layer, then rerun\n\treturn err\n}","preventionTips":["Store load flags as a JSON file or single-quoted heredoc to avoid shell quote-stripping.","Validate the flag with jq or json.Unmarshal in startup scripts.","Escape double quotes correctly for systemd/Helm/shell layers between config and process."],"tags":["restore","mysqlshell","json","configuration"],"backgroundTag":"invalid-json-config","analyzedSha":"01a25a7d176f94613b8d59d799f438380a8760e4","analyzedAt":"2026-09-01T17:28:30.605Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}