diff --git a/src/main/java/it/inaf/oats/vospace/BaseNodeController.java b/src/main/java/it/inaf/oats/vospace/BaseNodeController.java
index a9661a1fb5766db501569f8574f3b0c56dd900ce..d612a56591fa7c749c246e54176d1efe5b3d6750 100644
--- a/src/main/java/it/inaf/oats/vospace/BaseNodeController.java
+++ b/src/main/java/it/inaf/oats/vospace/BaseNodeController.java
@@ -1,6 +1,7 @@
 package it.inaf.oats.vospace;
 
 import it.inaf.oats.vospace.datamodel.NodeUtils;
+import it.inaf.oats.vospace.exception.InvalidURIException;
 import javax.servlet.http.HttpServletRequest;
 import org.springframework.beans.factory.annotation.Autowired;
 
@@ -9,20 +10,16 @@ public abstract class BaseNodeController {
     @Autowired
     private HttpServletRequest servletRequest;
 
-    
     protected String getPath() {
-        
         String requestURL = servletRequest.getRequestURL().toString();
-        
-        return NodeUtils.getPathFromRequestURLString(requestURL);
-        
+        try {
+            return NodeUtils.getPathFromRequestURLString(requestURL);
+        } catch (IllegalArgumentException ex) {
+            throw new InvalidURIException(ex);
+        }
     }
-    
-    
 
     protected String getParentPath(String path) {
-
         return NodeUtils.getParentPath(path);
     }
-    
 }
diff --git a/src/main/java/it/inaf/oats/vospace/CreateNodeController.java b/src/main/java/it/inaf/oats/vospace/CreateNodeController.java
index 488d2c141ce1886a9fe8a4e8bfe4a852e9f848cd..b3250614ff98a092b6ec8a2ea6b63e27c92d5c6c 100644
--- a/src/main/java/it/inaf/oats/vospace/CreateNodeController.java
+++ b/src/main/java/it/inaf/oats/vospace/CreateNodeController.java
@@ -1,7 +1,6 @@
 package it.inaf.oats.vospace;
 
 import it.inaf.ia2.aa.data.User;
-import it.inaf.oats.vospace.datamodel.NodeProperties;
 import it.inaf.oats.vospace.datamodel.NodeUtils;
 import net.ivoa.xml.vospace.v2.Node;
 import org.springframework.http.MediaType;
@@ -9,15 +8,17 @@ import org.springframework.web.bind.annotation.RequestBody;
 import org.springframework.web.bind.annotation.RestController;
 import org.springframework.beans.factory.annotation.Autowired;
 import it.inaf.oats.vospace.persistence.NodeDAO;
-import java.util.List;
 import org.springframework.beans.factory.annotation.Value;
 import org.springframework.web.bind.annotation.PutMapping;
 import it.inaf.oats.vospace.exception.*;
-import java.util.stream.Collectors;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 
 @RestController
 public class CreateNodeController extends BaseNodeController {
 
+    private static final Logger LOG = LoggerFactory.getLogger(CreateNodeController.class);
+    
     @Autowired
     private NodeDAO nodeDao;
 
@@ -30,6 +31,8 @@ public class CreateNodeController extends BaseNodeController {
     public Node createNode(@RequestBody Node node, User principal) {
 
         String path = getPath();
+        
+        LOG.debug("createNode called for path {}", path);
 
         // Validate payload node URI
         if (!isValidURI(node.getUri())) {
@@ -93,9 +96,5 @@ public class CreateNodeController extends BaseNodeController {
         // form vos://authority[!~]somepath/mynode..."
 
         return nodeURI.replaceAll("vos://[^/]+", "").equals(path);
-
     }
-
-    
-
 }
diff --git a/src/main/java/it/inaf/oats/vospace/DeleteNodeController.java b/src/main/java/it/inaf/oats/vospace/DeleteNodeController.java
index eae1a869d26f51e995afca9c38011bd51e087012..168700a44910201b561e6755566bcdb167801d45 100644
--- a/src/main/java/it/inaf/oats/vospace/DeleteNodeController.java
+++ b/src/main/java/it/inaf/oats/vospace/DeleteNodeController.java
@@ -1,36 +1,29 @@
-/*
- * To change this license header, choose License Headers in Project Properties.
- * To change this template file, choose Tools | Templates
- * and open the template in the editor.
- */
 package it.inaf.oats.vospace;
 
 import it.inaf.ia2.aa.data.User;
-import it.inaf.oats.vospace.datamodel.NodeProperties;
 import it.inaf.oats.vospace.datamodel.NodeUtils;
-import it.inaf.oats.vospace.exception.ContainerNotFoundException;
-import it.inaf.oats.vospace.exception.InternalFaultException;
 import it.inaf.oats.vospace.exception.LinkFoundException;
 import it.inaf.oats.vospace.exception.NodeNotFoundException;
 import it.inaf.oats.vospace.exception.PermissionDeniedException;
 import it.inaf.oats.vospace.persistence.NodeDAO;
-import java.util.ArrayList;
 import java.util.List;
-import java.util.stream.Collectors;
 import javax.servlet.http.HttpServletRequest;
 import net.ivoa.xml.vospace.v2.Node;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.http.HttpStatus;
 import org.springframework.http.MediaType;
 import org.springframework.http.ResponseEntity;
 import org.springframework.web.bind.annotation.DeleteMapping;
-import org.springframework.web.bind.annotation.GetMapping;
 import org.springframework.web.bind.annotation.RestController;
 
 
 @RestController
 public class DeleteNodeController extends BaseNodeController  {
     
+    private static final Logger LOG = LoggerFactory.getLogger(DeleteNodeController.class);
+    
     @Autowired
     private NodeDAO nodeDAO;
 
@@ -39,6 +32,7 @@ public class DeleteNodeController extends BaseNodeController  {
     public ResponseEntity<String> deleteNode(HttpServletRequest request, User principal) {
         
         String path = getPath();
+        LOG.debug("deleteNode called for path {}", path);
         
         // Check if the node is present, 
         // if the node does not exist the service SHALL throw a HTTP 404 status code 
@@ -53,7 +47,7 @@ public class DeleteNodeController extends BaseNodeController  {
         // status code including a LinkFound fault in the entity-body if either /a 
         // or /a/b are LinkNodes.
         List<String> pathComponents = NodeUtils.subPathComponents(path);
-        if (pathComponents.size() == 0) { 
+        if (pathComponents.isEmpty()) { 
             
             // Manage root node
             throw new PermissionDeniedException("root");
diff --git a/src/main/java/it/inaf/oats/vospace/ListNodeController.java b/src/main/java/it/inaf/oats/vospace/ListNodeController.java
index e35793314cbb9cd049420c2aefccabbc812efe98..4ac5fc58da6b04966162f337894361797793db9b 100644
--- a/src/main/java/it/inaf/oats/vospace/ListNodeController.java
+++ b/src/main/java/it/inaf/oats/vospace/ListNodeController.java
@@ -10,11 +10,15 @@ import net.ivoa.xml.vospace.v2.Node;
 
 import it.inaf.oats.vospace.persistence.NodeDAO;
 import javax.servlet.http.HttpServletRequest;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 import org.springframework.http.MediaType;
 
 @RestController
 public class ListNodeController extends BaseNodeController {
 
+    private static final Logger LOG = LoggerFactory.getLogger(ListNodeController.class);
+    
     @Autowired
     private NodeDAO nodeDAO;
 
@@ -22,6 +26,7 @@ public class ListNodeController extends BaseNodeController {
             produces = {MediaType.APPLICATION_XML_VALUE, MediaType.APPLICATION_JSON_VALUE, MediaType.TEXT_XML_VALUE})
     public ResponseEntity<Node> listNode(HttpServletRequest request) {
         String path = getPath();
+        LOG.debug("listNode called for path {}", path);
         return ResponseEntity.ok(nodeDAO.listNode(path)
                 .orElseThrow(() -> new NodeNotFoundException(path)));
     }
diff --git a/src/main/java/it/inaf/oats/vospace/UriService.java b/src/main/java/it/inaf/oats/vospace/UriService.java
index 0bcbf2b28412d6acde499518305afd3249c8b0b3..a2aa7c15d7ce303fa3a045e6adf48bae6af7054c 100644
--- a/src/main/java/it/inaf/oats/vospace/UriService.java
+++ b/src/main/java/it/inaf/oats/vospace/UriService.java
@@ -4,6 +4,8 @@ import it.inaf.ia2.aa.ServletRapClient;
 import it.inaf.ia2.aa.data.User;
 import it.inaf.ia2.rap.client.call.TokenExchangeRequest;
 import it.inaf.oats.vospace.datamodel.NodeProperties;
+import static it.inaf.oats.vospace.datamodel.NodeUtils.urlEncodePath;
+import it.inaf.oats.vospace.exception.NodeNotFoundException;
 import it.inaf.oats.vospace.persistence.NodeDAO;
 import java.util.ArrayList;
 import java.util.List;
@@ -65,13 +67,11 @@ public class UriService {
 
         String relativePath = transfer.getTarget().substring("vos://".length() + authority.length());
 
-        // TODO handle node not found
-        Node node = nodeDao.listNode(relativePath).get();
+        Node node = nodeDao.listNode(relativePath).orElseThrow(() -> new NodeNotFoundException(relativePath));
 
         // TODO build the path according to node type
         //
-        // TODO add token for authenticated access
-        String endpoint = fileServiceUrl + relativePath + "?jobId=" + job.getJobId();
+        String endpoint = fileServiceUrl + urlEncodePath(relativePath) + "?jobId=" + job.getJobId();
 
         if (!"true".equals(NodeProperties.getNodePropertiesListByURI(node, NodeProperties.PUBLIC_READ_URI))) {
             endpoint += "&token=" + getEndpointToken(fileServiceUrl + relativePath);
diff --git a/src/main/java/it/inaf/oats/vospace/exception/InvalidURIException.java b/src/main/java/it/inaf/oats/vospace/exception/InvalidURIException.java
index c303711a13976bfffe2263868204b92f3c1dd540..085d10211ecbc9cc3184f85582b174ceaaa41fa5 100644
--- a/src/main/java/it/inaf/oats/vospace/exception/InvalidURIException.java
+++ b/src/main/java/it/inaf/oats/vospace/exception/InvalidURIException.java
@@ -7,12 +7,15 @@ import org.springframework.web.bind.annotation.ResponseStatus;
 public class InvalidURIException extends VoSpaceException {
 
     public InvalidURIException(String URI, String path) {
-        super("InvalidURI. Payload node URI: " + URI + 
-                " is not consistent with request path: " + path);
+        super("InvalidURI. Payload node URI: " + URI
+                + " is not consistent with request path: " + path);
     }
-    
-    public InvalidURIException(String URI)
-    {
-        super("InvalidURI. URI: "+URI+ " is not in a valid format");
+
+    public InvalidURIException(String URI) {
+        super("InvalidURI. URI: " + URI + " is not in a valid format");
+    }
+
+    public InvalidURIException(IllegalArgumentException ex) {
+        super("InvalidURI. " + ex.getMessage());
     }
 }
diff --git a/src/test/java/it/inaf/oats/vospace/CreateNodeControllerTest.java b/src/test/java/it/inaf/oats/vospace/CreateNodeControllerTest.java
index ab2dd4463749d0c294ccf5c25b5f79fe97c28f84..27058b09be18a34e4ee6fd68f38cfc8fb4567e73 100644
--- a/src/test/java/it/inaf/oats/vospace/CreateNodeControllerTest.java
+++ b/src/test/java/it/inaf/oats/vospace/CreateNodeControllerTest.java
@@ -2,6 +2,7 @@ package it.inaf.oats.vospace;
 
 import it.inaf.oats.vospace.persistence.NodeDAO;
 import java.io.InputStream;
+import java.net.URI;
 import java.nio.charset.StandardCharsets;
 import net.ivoa.xml.vospace.v2.Property;
 import net.ivoa.xml.vospace.v2.UnstructuredDataNode;
@@ -23,9 +24,9 @@ import org.springframework.boot.test.mock.mockito.SpyBean;
 import net.ivoa.xml.vospace.v2.ContainerNode;
 import net.ivoa.xml.vospace.v2.LinkNode;
 import java.util.List;
-import it.inaf.ia2.aa.data.User;
 import java.util.Optional;
 import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertTrue;
 import org.mockito.ArgumentCaptor;
 import static org.mockito.Mockito.times;
 import org.springframework.test.context.TestPropertySource;
@@ -83,12 +84,6 @@ public class CreateNodeControllerTest {
         return parentNode;
     }
 
-    private User getUser() {
-        User user = new User();
-        user.setGroups(List.of("test1"));
-        return user;
-    }
-
     @Test
     public void testFromJsonToXml() throws Exception {
         String requestBody
@@ -299,6 +294,24 @@ public class CreateNodeControllerTest {
         assertEquals("/mydata1/anothernode", argCaptor.getAllValues().get(0));
         assertEquals("/mydata1", argCaptor.getAllValues().get(1));
     }
+    
+    @Test
+    public void testIllegalChars() throws Exception {
+
+        String requestBody = getResourceFileContent("create-unstructured-data-node.xml")
+                .replace("/mydata1", "/mydata1/?anothernode");
+
+        String message = mockMvc.perform(put(new URI("/nodes/mydata1/%3Fanothernode"))
+                .header("Authorization", "Bearer user2_token")
+                .content(requestBody)
+                .contentType(MediaType.APPLICATION_XML)
+                .accept(MediaType.APPLICATION_XML))
+                .andDo(print())
+                .andExpect(status().isBadRequest())
+                .andReturn().getResolvedException().getMessage();
+
+        assertTrue(message.contains("contains an illegal character"));
+    }
 
     private void verifyArguments() {
         verify(controller).createNode(