{"record":{"id":"02bd0bf49d4e8b56","repo":"hashicorp/nomad","slug":"volume-q-is-already-published-at-target-path-q-b","errorCode":null,"errorMessage":"volume %q is already published at target path %q but with capabilities or a read_only setting incompatible with this request: %v","messagePattern":"volume %q is already published at target path %q but with capabilities or a read_only setting incompatible with this request: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"plugins/csi/client.go","lineNumber":876,"sourceCode":"\nfunc (c *client) NodePublishVolume(ctx context.Context, req *NodePublishVolumeRequest, opts ...grpc.CallOption) error {\n\tif err := c.ensureConnected(ctx); err != nil {\n\t\treturn err\n\t}\n\tif err := req.Validate(); err != nil {\n\t\treturn fmt.Errorf(\"validation error: %v\", err)\n\t}\n\n\t// NodePublishVolume's response contains no extra data. If err == nil, we were\n\t// successful.\n\t_, err := c.nodeClient.NodePublishVolume(ctx, req.ToCSIRepresentation(), opts...)\n\tif err != nil {\n\t\tcode := status.Code(err)\n\t\tswitch code {\n\t\tcase codes.NotFound:\n\t\t\terr = fmt.Errorf(\"volume %q could not be found: %v\", req.ExternalID, err)\n\t\tcase codes.AlreadyExists:\n\t\t\terr = fmt.Errorf(\n\t\t\t\t\"volume %q is already published at target path %q but with capabilities or a read_only setting incompatible with this request: %v\",\n\t\t\t\treq.ExternalID, req.TargetPath, err)\n\t\tcase codes.FailedPrecondition:\n\t\t\terr = fmt.Errorf(\"volume %q does not have MULTI_NODE volume capability: %v\",\n\t\t\t\treq.ExternalID, err)\n\t\tcase codes.Internal:\n\t\t\terr = fmt.Errorf(\"node plugin returned an internal error, check the plugin allocation logs for more information: %v\", err)\n\t\t}\n\t}\n\treturn err\n}\n\nfunc (c *client) NodeUnpublishVolume(ctx context.Context, volumeID, targetPath string, opts ...grpc.CallOption) error {\n\tif err := c.ensureConnected(ctx); err != nil {\n\t\treturn err\n\t}\n\t// These errors should not be returned during production use but exist as aids\n\t// during Nomad development","sourceCodeStart":858,"sourceCodeEnd":894,"githubUrl":"https://github.com/hashicorp/nomad/blob/482b49bf1aec006f089bcfc7e632d8f6ac303e5e/plugins/csi/client.go#L858-L894","documentation":"NodePublishVolume wraps gRPC AlreadyExists errors with this message. The volume is already mounted at the target path, but the existing mount's volume capability (ACCESS_MODE, MULTI_NODE setting) or read_only flag differs from what the current request asks for, so the CSI spec forbids reusing it.","triggerScenarios":"Calling NodePublishVolume for a volume already published at req.TargetPath when the new request's VolumeCapability or RO flag is incompatible with the existing publication (codes.AlreadyExists).","commonSituations":"A task group spec changed a volume's access mode (e.g. SINGLE_NODE_WRITER -> MULTI_NODE_MULTI_WRITER) or mount flags while the old mount remained; leftover mount from a previous allocation at the same host path; accidentally publishing the same volume with different read_only settings to the same target path.","solutions":["Stop/unmount the existing publication (NodeUnpublishVolume or restart the allocation) before republishing with new capabilities.","Make all consumers use a consistent volume capability and read_only setting; update the Nomad job spec to match the existing mount.","Manually unmount and clean the stale target path on the host (umount; verify /proc/mounts) if a previous allocation leaked the mount.","If needed, detach/unpublish from the storage side and retry publish with the desired capabilities."],"exampleFix":"// before: republishing with a different access mode at a live mount\nreq.VolumeCapability.AccessMode.Mode = csipbv1.VolumeCapability_AccessMode_MULTI_NODE_MULTI_WRITER\nc.NodePublishVolume(ctx, req)\n// after: unpublish then republish consistently\nif err := c.NodeUnpublishVolume(ctx, volumeID, targetPath); err != nil { return err }\nreq.VolumeCapability.AccessMode.Mode = csipbv1.VolumeCapability_AccessMode_MULTI_NODE_MULTI_WRITER\nreturn c.NodePublishVolume(ctx, req)","handlingStrategy":"validation","validationCode":"// before publishing, verify no existing mount with different capabilities\nif mountedAt(targetPath) && existingMode != req.Capability.AccessMode.Mode {\n\treturn fmt.Errorf(\"unpublish existing mount at %s before republishing\", targetPath)\n}","typeGuard":"func isCSIAlreadyExists(err error) bool { return status.Code(err) == codes.AlreadyExists }","tryCatchPattern":"if err := client.NodePublishVolume(ctx, req); err != nil && strings.Contains(err.Error(), \"already published\") {\n\t_ = client.NodeUnpublishVolume(ctx, req.ExternalID, req.TargetPath)\n\treturn client.NodePublishVolume(ctx, req) // republish with consistent caps\n}","preventionTips":["Keep volume capability and read_only settings identical across all consumers of a volume.","Don't change access modes while allocations using the volume are running.","Clean stale mounts on host drain/restart before rescheduling."],"tags":["csi","volume","grpc","mount"],"backgroundTag":"csi-already-published-incompatible-capability","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"}