clojure/clojure · error · RuntimeException

No reader function for tag

Error message

No reader function for tag ${tag}

What it means

When reading a tagged literal `#tag value`, the reader looks up `tag` first in the `data_readers` map (from *data-readers* and data_readers.clj on the classpath), then in `*default-data-reader-fn*`. If neither provides an IFn, it throws RuntimeException "No reader function for tag <tag>". This keeps unknown tags from being silently ignored, since the value cannot be constructed.

Solutions

  1. Bind *data-readers* with a mapping for the tag: `(binding [*data-readers* {'mytag my-fn}] (read-string s))`.
  2. Add a data_readers.clj (or data_readers.cljc) resource on the classpath mapping the tag symbol to a reader function.
  3. Set *default-data-reader-fn* to a fallback handler for unknown tags.
  4. Require the namespace that registers the tag before reading (e.g. via :require in your ns).

Example fix

// before
(read-string "#mytag {:a 1}")
;; after
(binding [*data-readers* {'mytag (fn [v] (->MyTag v))}]
  (read-string "#mytag {:a 1}"))
Defensive patterns

Strategy: try-catch

Validate before calling

(defn tag-known? [tag]
  (or (contains? *data-readers* tag)
      (some? *default-data-reader-fn*)))

Try / catch

(try
  (read-string s)
  (catch RuntimeException e
    (if (re-find #"No reader function for tag" (.getMessage e))
      (do (require '[my.ns.readers]) (read-string s))
      (throw e))))

Prevention

When it happens

Trigger: Reading `#mytag {...}` where `mytag` has no registered data reader: not in *data-readers*, no data_readers.clj on classpath, and *default-data-reader-fn* is nil; also loading an edn/serialized file produced by a different project with custom tags.

Common situations: Sharing edn/data files across projects where the consumer lacks the producer's data readers; forgetting to require the namespace that registers the reader; tag renamed between library versions.

Understand the failure class

Background: 'Could not be found', 'does not exist', 'not found in database': the resource-not-found family when an ID, slug, key, or URI lookup comes back empty — this error's family across 20 libraries.

Related errors


AI-assisted analysis of clojure/clojure@f3b143341d (2026-09-09). Data as JSON: /api/errors/72c6be3d79cb0245. Report an issue: GitHub.

Appendix: source

Thrown at src/jvm/clojure/lang/LispReader.java:1447

		} else {
			return sym.getName().contains(".") ? readRecord(form, sym, opts, pendingForms) : readTagged(form, sym, opts, pendingForms);
		}

	}

	private Object readTagged(Object o, Symbol tag, Object opts, Object pendingForms){

		ILookup data_readers = (ILookup)RT.DATA_READERS.deref();
		IFn data_reader = (IFn)RT.get(data_readers, tag);
		if(data_reader == null){
		data_readers = (ILookup)RT.DEFAULT_DATA_READERS.deref();
		data_reader = (IFn)RT.get(data_readers, tag);
		if(data_reader == null){
		IFn default_reader = (IFn)RT.DEFAULT_DATA_READER_FN.deref();
		if(default_reader != null)
			return default_reader.invoke(tag, o);
		else
			throw new RuntimeException("No reader function for tag " + tag.toString());
		}
		}

		return data_reader.invoke(o);
	}

	private Object readRecord(Object form, Symbol recordName, Object opts, Object pendingForms){
        boolean readeval = RT.booleanCast(RT.READEVAL.deref());

	    if(!readeval)
		    {
		    throw Util.runtimeException("Record construction syntax can only be used when *read-eval* == true");
		    }

		Class recordClass = RT.classForNameNonLoading(recordName.toString());


		boolean shortForm = true;

View on GitHub (pinned to f3b143341d)