{"record":{"id":"c07e44b7ddaa64ec","repo":"hashicorp/nomad","slug":"provider-q-for-secret-q-response-contained-error","errorCode":null,"errorMessage":"provider %q for secret %q response contained error: %q","messagePattern":"provider %q for secret %q response contained error: %q","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"client/allocrunner/taskrunner/secrets/plugin_provider.go","lineNumber":58,"sourceCode":"\t\tsecretName: secretName,\n\t\tpath:       path,\n\t\tenv:        env,\n\t}\n}\n\nfunc (p *ExternalPluginProvider) InterpolateEnv(interpolate func(string) string) {\n\tfor key, value := range p.env {\n\t\tp.env[key] = interpolate(value)\n\t}\n}\n\nfunc (p *ExternalPluginProvider) Fetch(ctx context.Context) (map[string]string, error) {\n\tresp, err := p.plugin.Fetch(ctx, p.path, p.env)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed executing plugin %q for secret %q: %w\", p.pluginName, p.secretName, err)\n\t}\n\tif resp.Error != nil {\n\t\treturn nil, fmt.Errorf(\"provider %q for secret %q response contained error: %q\", p.pluginName, p.secretName, *resp.Error)\n\t}\n\n\tformatted := make(map[string]string, len(resp.Result))\n\tfor k, v := range resp.Result {\n\t\tformatted[fmt.Sprintf(\"secret.%s.%s\", p.secretName, k)] = v\n\t}\n\n\treturn formatted, nil\n}\n","sourceCodeStart":40,"sourceCodeEnd":68,"githubUrl":"https://github.com/hashicorp/nomad/blob/482b49bf1aec006f089bcfc7e632d8f6ac303e5e/client/allocrunner/taskrunner/secrets/plugin_provider.go#L40-L68","documentation":"The external secret plugin executed successfully but explicitly reported a logical failure in its FetchResponse.Error field. Nomad surfaces that message verbatim as a provider error for the specific secret. Unlike error 705, the plugin process ran fine — it is telling Nomad the secret could not be retrieved/produced for an application-level reason.","triggerScenarios":"Calling ExternalPluginProvider.Fetch when the plugin returns a response whose Error pointer is non-nil, e.g. secret path not found, auth to the secret backend denied, or the requested secret key absent.","commonSituations":"Wrong secret path in the task's secrets block; revoked or expired plugin credentials to the upstream vault; secret deleted or rotated out from under a running allocation; typo in secret key/field name.","solutions":["Read the quoted message from the plugin — it states the actual reason (not found, denied, etc.) and fix the secret path or permissions.","Verify the secret exists at the given path in the upstream secret backend.","Check/renew the credentials the plugin uses to reach the backend.","Re-run the task after correcting the secrets block so the hook refetches."],"exampleFix":"// before: task secrets block referencing a nonexistent path\nsecrets { env = \"db_pass\" path = \"kv/prod/dbpass\" }\n// after: corrected path that exists in the backend\nsecrets { env = \"db_pass\" path = \"kv/prod/db/password\" }","handlingStrategy":"validation","validationCode":"// validate the secret path exists before referencing it in the job\nv, err := vaultClient.KVv2(\"kv\").Get(ctx, \"prod/db/password\")\nif err != nil {\n    return fmt.Errorf(\"secret path referenced in nomad job does not exist: %w\", err)\n}","typeGuard":"// guard the plugin response before use\nfunc responseOK(resp *FetchResponse) bool {\n    return resp != nil && resp.Error == nil\n}","tryCatchPattern":null,"preventionTips":["Lint job files against the secret backend (path + keys) in CI before nomad job run.","Rotate plugin credentials before expiry and alert on upcoming expirations.","Use distinct paths/namespaces per environment to avoid cross-env path mistakes.","Prefer dynamic job templating (consul-template/vault stanza) over hard-coded paths."],"tags":["nomad","secrets","plugin"],"backgroundTag":"secret-plugin-response-error","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"}