Merkledag Node Error

So, I downloaded and set up ipfs on my Ubuntu 16.04 laptop and started going through the quick-start. The first few examples went fine, but when I tried to do an 'ipfs ls ', I received this error: “Error: merkledag node was not a directory or sharding”. What does this mean and how can I fix it?

Hm, seems like the hash you were trying to get a directory listing of was not a directory.

Could you post the hash here so we can double-check?

OK, when I execute this, I get the expected result:

ipfs cat /ipfs/QmVLDAhCY3X9P2uRudKAryuQFPM5zqA3Yij1dY8FpGbL7T/quick-start

yet when I enter this, I get that error:

ipfs cat /ipfs/QmVLDAhCY3X9P2uRudKAryuQFPM5zqA3Yij1dY8FpGbL7T

I’m getting a different error: Error: this dag node is a directory … but yeah, you can’t cat a directory.

1 Like

OK, thanks! Hmm . . . so, how can I tell the difference between a directory and a file by looking at the hash? Also, once I add a bunch of stuff, how can I see what I put in my local ipfs repository? I did an ‘ipfs refs’ but it gives me the hashes, but I don’t always remember what they are associated with. Or am I thinking about this all wrong?

To my knowledge, you can’t. And you shouldn’t, because in the Unix world, which IPFS is based on, there are only files. A directory is a file. People tend to forget that. But you can run it like this: ipfs ls QmQ5vhrL7uv6tuoN9KeVBwd4PwfQkXdVVmDLUZuTNxqgvm 2>/dev/null, and if it returns nothing, then it’s a standard file or empty directory. If it returns something, then it’s a directory file, e.g. ipfs ls QmVLDAhCY3X9P2uRudKAryuQFPM5zqA3Yij1dY8FpGbL7T 2>/dev/null. If the resulting list has the value 0 (zero) in the second column, then it’s a subdirectory.

There’s also ipfs object links <hash>, with no need for 2>/dev/null, because it’ll just print nothing, if it’s a file, but as before, you can’t distinguish between a file and an empty directory, and the object command will be deprecated in favor of dag, i.e. you can look at an object with ipfs dag get <hash>, and if it’s a directory, the output will read {"data":"CAE=","links":[]}, with the child objects within the square brackets, and nothing within the square brackets, if it’s an empty directory. If it’s a file, it will just give you the raw data, and "links":[] at the end.

It think that ipfs dag needs a lot more options, like stat etc., and maybe even a way to print out, if it’s a directory or a file. That would be awesome.

Objects are just represented by their hash. If you want to retain the filename and extension, you need to ipfs add -w the file, which will wrap it into a directory. Personally, I don’t like this default way of just adding files into the main data pool, wrap or no-wrap, so I use the MFS, i.e. when I add files to the IPFS, I always add a references to them in my local mutable filesystem with ipfs files cp /ipfs/<hash> /added/Filename. (You can automate that easily.) In this case you need to first create the MFS folder “added” with ipfs files mkdir /added.

If you have unknown IPFS objects, you might have some luck with ipfs cat <hash> | file - which won’t work on every filetype, though. Sometimes, e.g. with DMG files on macOS, it’ll just say /dev/stdin: data.

To determine whether an IPFS object is a file or directory or empty directory, I guess you could put this function into your zshrc or bashrc… don’t know if it’ll work all the time, on all objects, and what ipfs updates might do to it. (Note: BSD Unix on macOS)

ipftype() {
if [[ $(ipfs 2>/dev/null) == "" ]] ; then
	echo -e "IPFS is either not installed or not in your \$PATH"
	return 1
fi
if [[ $(ps aux | grep "ipfs daemon" | grep -v "grep.*ipfs daemon" 2>/dev/null) == "" ]] ; then
	echo -e "IPFS daemon is not running"
	return 1
fi
if [[ $# -eq 0 ]] ; then
	echo -e "No IPFS hash specified.\nUsage:\tipftype <hash>"
	return 1
fi
for hash in "$@" ; do
	daginfo=$(ipfs dag get $hash 2>/dev/null)
	if [[ $daginfo == "" ]] ; then
		echo -e "$hash: error"
		continue
	fi
	if [[ $(echo "$daginfo" | grep "\"data\":\"CAE=") != "" ]] ; then
		if [[ $(echo "$daginfo" | grep "\"links\":\[\]") == "" ]] ; then
			echo -e "$hash: directory"
		else
			echo -e "$hash: empty directory"
		fi
	else
		echo -e "$hash: file"
	fi
done
}

EDIT: some corrections/additions