{"record":{"id":"21d1f80d19fee8fe","repo":"d2lang/d2","slug":"failed-to-unmarshal-json-w","errorCode":null,"errorMessage":"failed to unmarshal json: %w","messagePattern":"failed to unmarshal json: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"d2plugin/exec.go","lineNumber":67,"sourceCode":"\tctx, cancel := context.WithTimeout(ctx, time.Second*10)\n\tdefer cancel()\n\tcmd := exec.CommandContext(ctx, p.path, \"flags\")\n\tdefer xdefer.Errorf(&err, \"failed to run %v\", cmd.Args)\n\n\tstdout, err := cmd.Output()\n\tif err != nil {\n\t\tee := &exec.ExitError{}\n\t\tif errors.As(err, &ee) && len(ee.Stderr) > 0 {\n\t\t\treturn nil, fmt.Errorf(\"%v\\nstderr:\\n%s\", ee, ee.Stderr)\n\t\t}\n\t\treturn nil, err\n\t}\n\n\tvar flags []PluginSpecificFlag\n\n\terr = json.Unmarshal(stdout, &flags)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to unmarshal json: %w\", err)\n\t}\n\n\treturn flags, nil\n}\n\nfunc (p *execPlugin) HydrateOpts(opts []byte) error {\n\tif opts != nil {\n\t\tvar execOpts map[string]interface{}\n\t\terr := json.Unmarshal(opts, &execOpts)\n\t\tif err != nil {\n\t\t\treturn xmain.UsageErrorf(\"non-exec layout options given for exec\")\n\t\t}\n\n\t\tallString := make(map[string]string)\n\t\tfor k, v := range execOpts {\n\t\t\tswitch vt := v.(type) {\n\t\t\tcase string:\n\t\t\t\tallString[k] = vt","sourceCodeStart":49,"sourceCodeEnd":85,"githubUrl":"https://github.com/d2lang/d2/blob/0d69dca6f532ceaeacd615d35d1eaa41a238ffdb/d2plugin/exec.go#L49-L85","documentation":"After Flags runs the plugin successfully, its stdout must be a JSON array of PluginSpecificFlag. This error wraps json.Unmarshal failures, meaning the plugin emitted non-JSON or schema-mismatched output.","triggerScenarios":"plugin.Flags() when the plugin's flags subcommand prints logs, warnings, or malformed JSON to stdout instead of the expected PluginSpecificFlag JSON array.","commonSituations":"Plugin writing human-readable logging to stdout instead of stderr; older plugin binary emitting an outdated flag schema.","solutions":["Check the raw stdout of the plugin's flags subcommand for stray non-JSON output","Rebuild/reinstall the plugin to match the current d2 plugin protocol","Fix the plugin so logs go to stderr and only JSON goes to stdout"],"exampleFix":"// before (in plugin)\nfmt.Println(\"loading flags...\")\njson.NewEncoder(os.Stdout).Encode(flags)\n// after\nfmt.Fprintln(os.Stderr, \"loading flags...\")\njson.NewEncoder(os.Stdout).Encode(flags)","handlingStrategy":"try-catch","validationCode":"out, err := exec.Command(pluginPath, \"flags\").Output()\nif err == nil && !json.Valid(out) {\n    return fmt.Errorf(\"plugin flags output is not valid JSON\")\n}","typeGuard":"func isUnmarshalError(err error) bool {\n    return strings.Contains(err.Error(), \"failed to unmarshal json\")\n}","tryCatchPattern":"flags, err := plugin.Flags()\nif err != nil {\n    if strings.Contains(err.Error(), \"failed to unmarshal json\") {\n        return fmt.Errorf(\"plugin %s emits invalid JSON on stdout; reinstall it\", plugin.Path)\n    }\n    return err\n}","preventionTips":["Plugins must log to stderr, never stdout","Pin plugin versions alongside d2 versions","Validate plugin output in a CI smoke test"],"tags":["plugin","json","unmarshal"],"backgroundTag":"json-unmarshal-failed","analyzedSha":"0d69dca6f532ceaeacd615d35d1eaa41a238ffdb","analyzedAt":"2026-08-31T12:19:21.182Z","schemaVersion":2},"datasetVersion":"2026-08-31T14:17:45.589Z"}