factor out some duplication, improve error handling