{"record":{"id":"1649b936b9ff0119","repo":"hashicorp/nomad","slug":"error-fingerprinting-plugin-q-w","errorCode":null,"errorMessage":"error fingerprinting plugin %q: %w","messagePattern":"error fingerprinting plugin %q: %w","errorType":"error_code","errorClass":null,"httpStatus":null,"severity":"error","filePath":"client/hostvolumemanager/host_volume_plugin.go","lineNumber":295,"sourceCode":"// {\"version\": \"0.0.1\"}\n// The version value should be a valid version number as allowed by\n// version.NewVersion()\n//\n// Must complete within 5 seconds\nfunc (p *HostVolumePluginExternal) Fingerprint(ctx context.Context) (*PluginFingerprint, error) {\n\tctx, cancel := context.WithTimeout(ctx, 5*time.Second)\n\tdefer cancel()\n\tcmd := exec.CommandContext(ctx, p.Executable, \"fingerprint\")\n\tcmd.Env = []string{EnvOperation + \"=fingerprint\"}\n\tstdout, stderr, err := runCommand(cmd)\n\tlog := p.log.With(\n\t\t\"operation\", \"fingerprint\",\n\t\t\"stdout\", string(stdout),\n\t\t\"stderr\", string(stderr),\n\t)\n\tif err != nil {\n\t\tlog.Error(\"error running plugin\", \"error\", err)\n\t\treturn nil, fmt.Errorf(\"error fingerprinting plugin %q: %w\", p.ID, err)\n\t}\n\tfprint := &PluginFingerprint{}\n\tif err := json.Unmarshal(stdout, fprint); err != nil {\n\t\terr = fmt.Errorf(\"error parsing fingerprint output as json: %w\", err)\n\t\tlog.Error(\"error parsing plugin output\", \"error\", err)\n\t\treturn nil, err\n\t}\n\treturn fprint, nil\n}\n\n// Create calls the executable with the following parameters:\n// arguments: $1=create\n// environment:\n// - DHV_OPERATION=create\n// - DHV_VOLUMES_DIR={directory to put the volume in}\n// - DHV_PLUGIN_DIR={path to directory containing plugins}\n// - DHV_NAMESPACE={volume namespace}\n// - DHV_VOLUME_NAME={name from the volume specification}","sourceCodeStart":277,"sourceCodeEnd":313,"githubUrl":"https://github.com/hashicorp/nomad/blob/482b49bf1aec006f089bcfc7e632d8f6ac303e5e/client/hostvolumemanager/host_volume_plugin.go#L277-L313","documentation":"Fingerprint runs the external plugin executable with the \"fingerprint\" operation and captures stdout/stderr. If the plugin process itself fails to run or exits with an error, Nomad logs it and returns this wrapped error naming the plugin ID. This is a wrapper around the plugin's execution failure — the real cause (non-zero exit, exec format error, timeout, crash) is in the wrapped error.","triggerScenarios":"Calling Fingerprint on a HostVolumePluginExternal when the child process invocation fails: plugin exits non-zero, binary has a bad shebang or wrong architecture (exec format error), plugin crashes, or the plugin writes malformed output causing a transport-level failure.","commonSituations":"Plugin binary built for the wrong OS/arch on the client node; plugin script with a shebang pointing to a missing interpreter (e.g. #!/usr/bin/python3 not installed); plugin itself erroring due to missing local configuration or dependencies; plugin killing itself on startup.","solutions":["Run the plugin binary manually with its fingerprint argument to reproduce the underlying failure and read its stderr.","Check the wrapped error: exec format error means wrong architecture — rebuild/re-download the plugin for the node's OS/arch.","Verify the interpreter in the plugin script's shebang exists on the node.","Confirm the plugin implements the fingerprint protocol and exits 0 while printing valid JSON to stdout."],"exampleFix":"// before: shebang points to absent interpreter\n#!/usr/bin/python3  # python3 not installed on node -> exec fails\n\n// after\n#!/usr/bin/env bash  # or install python3 on the node","handlingStrategy":"try-catch","validationCode":"func probePluginFingerprint(executable string) error {\n    ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)\n    defer cancel()\n    cmd := exec.CommandContext(ctx, executable, \"fingerprint\")\n    var stderr bytes.Buffer\n    cmd.Stderr = &stderr\n    if err := cmd.Run(); err != nil {\n        return fmt.Errorf(\"plugin fingerprint probe failed: %w; stderr: %s\", err, stderr.String())\n    }\n    return nil\n}","typeGuard":null,"tryCatchPattern":"if err != nil && strings.Contains(err.Error(), \"error fingerprinting plugin\") {\n    var exitErr *exec.ExitError\n    if errors.As(err, &exitErr) {\n        log.Error(\"plugin exited non-zero\", \"code\", exitErr.ExitCode(), \"stderr\", string(exitErr.Stderr))\n    } else if errors.Is(err, exec.ErrNotFound) || strings.Contains(err.Error(), \"exec format error\") {\n        log.Error(\"wrong arch/interpreter for plugin binary\")\n    }\n}","preventionTips":["Test plugin binaries manually on each node type before rollout.","Build/download plugins matching the node's OS/architecture.","Verify shebang interpreters exist on all client nodes.","Add a startup health probe that runs the plugin's fingerprint command."],"tags":["plugin","fingerprint","process-execution","host-volumes","go"],"backgroundTag":"process-exit-nonzero","analyzedSha":"482b49bf1aec006f089bcfc7e632d8f6ac303e5e","analyzedAt":"2026-09-04T07:54:14.808Z","contentChangedAt":"2026-09-04T07:54:14.808Z","schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}