Steps to fill out form 8802 for an S-Corp

At Inversoft, I’ve been working on getting our tax exemption for various European countries. This process requires a valid 8802 be submitted to the IRS. In return, the IRS will ship you out a shiny new form 6616 that you can snail mail across the Atlantic to the country of your choice. Yes, feel the sarcasm. This process is unbelievably dated, horrific, slow, lame, tree-killing, etc.

After talking to a number of accountants, some knowledgable and many not, I finally have the form filled out correctly and I’m about to drop it in the mail. Since this process is SOOOO painful, I figured I would give other S-Corp owners a heads up to hopefully save their sanity and a bunch of time.

Here’s exactly how to fill out form 8802:

  1. Put your full legal company name at the top under Applicant Name
  2. Put your S-Corp’s FEIN under Applicant’s U.S. taxpayer identification number
  3. Leave Line 1 blank
  4. Put in your company address on Line 2. I put in the exact same address on my S-Corp’s tax return since we haven’t moved this year. I don’t know if this is required, but might as well error on the safe side.
  5. Put in your company address on Line 3a
  6. Put in your name (that is you the shareholder/CEO) in Line 3b
  7. Checkmark Line 4f since you are an S-Corp
  8. Checkmark 1120s under the Yes. heading of Line 5
  9. Leave Line 6 blank
  10. Write 2018 on Line 7
  11. Put the last year and month you filed a tax return for on Line 8. This is the fiscal year end. So, in my case, the last year and month (fiscal year end) I filed was December 2017, so I put in 201712 and it MUST be in this format.
  12. Checkmark Income Tax on Line 9
  13. Write this exact text in two (2) separate lines on Line 10
    <Shareholder name> <Shareholder SSN> is a U.S. resident and will continue to be throughout the current tax year.
    <S-Corp name> <S-Corp FEIN> has filed its required return and the entity classification has not changed since the return was filed.
  14. Sign, date, add your phone number, name and title to the bottom
  15. Put your S-Corp name at to the top of the worksheet with your FEIN
  16. Put the current calendar year on the worksheet (still at the top section)
  17. Line 11 (on the worksheet) pick the country (or countries) you need and ask for 5 forms each
  18. Make sure you put in the correct total on Line 12

That’s all you need for form 8802. However, since you are filling this out for an S-Corp and according to tax law and treaties, S-Corp’s can’t claim exemptions or be identified as a corporation, you need to fill out a form 8821 also. The 8821 form is an authorization made by the shareholder in an S-Corp that is certifying that the form 8802 is correct. This is part of the perjury statement.

Filling out the form 8821 is also a nightmare and the instructions suck, so here are the steps for that form as well:

  1. Put your personal information (since you are the shareholder) on Line 1 (i.e. I put Brian Pontarelli here with my home address) including your SSN and phone number
  2. Leave Line 2 blank
  3. Don’t checkmark the checkbox on Line 3
  4. Write Income on Line 3a
  5. Write 1040 on Line 3b
  6. Write 2016, 2017, 2018, 2019, 2020 on Line 3c (or whatever years you need)
  7. Write Form 8802 on Line 3d
  8. Leave Line 4 blank
  9. Checkmark Line 5a
  10. Leave Line 6 blank
  11. Sign, date, print your name and put your title as CEO (or whatever it is)

NOTE: I’ve heard that form 8821 might not be necessary if there is only one shareholder and they are filing form 8802. I haven’t confirmed this, but if you are worried about it, just send in a 8821 regardless.

Also, I HIGHLY advise against faxing these forms in. I faxed them in and they were rejected by the IRS because the fax was illegible. Likely, their fax machine sucked or mine did. Regardless, save yourself the headache and mail them in. Or better yet, send them UPS, Fedex or USPS certified.

That should be it. I’m sending mine off next week, so if they aren’t accepted, I’ll update this post with any fixes I made.

Passport Launch Day!


Today is a huge day for Inversoft. We have successfully launched our second product, Passport. Passport is a revolutionary way to add login, registration and single sign-on to your applications. Rather than go into all the details here, check out the Inversoft blog post about the launch:

We also got some great press at eWeek and BetaNews. Check those articles out here:

What happened to Newegg?

Something is very wrong with Newegg. They used to be one of the best places to buy computers and electronics online. Now they are horrible.

Here’s my list of issues with them:

  • Lots of misleading product information.
    • We recently bought a monitor that claimed it supported 2560×1440 resolution when in fact it didn’t. The DisplayPort upscaled a 1080p signal to 1440 and it looked horrible. I had to read through a ton of the reviews to figured out that someone else had the same issue and they had done a bunch of research to find out the monitor didn’t truly support 1440.
  • They now charge large return shipping fees
  • They are also charge restocking fees on everything
  • Their support system is essentially worthless.
    • While you can contact support via a web form, it only allows 300 characters in the message. How can you possibly describe an issue clearly in 300 characters? That’s like 2 tweets.
What we were hoping would be a great price on an awesome monitor turned out to cost us nearly $80 for nothing. That’s the same as if I went to an ATM, pulled out four $20s and burned them.
Thanks Newegg for sucking. I’ll be buying everything on Amazon from now on.

Fixed Safari Autofill on localhost

After updating to Yosemite, which updated Safari to version 8, autofill stopped working for localhost. After some searching, it appears that this is due new security rules for Safari and OS X. Of course, that didn’t stop me from trying to get this working again as it made developing on localhost very cumbersome. The fix is pretty simple.

All you need to do is edit your /etc/hosts file and add a fully-qualified domain name alias for Here’s how mine looks:	localhost	broadcasthost
::1             localhost

I added the entry. Now I can access localhost using this alias and Safari nicely does autofill on form fields.

Mac command line gold!

Mac command line gold!

Copy a file to the clipboard:

$ cat ~/.zshrc | pbcopy

The contents of my .zshrc are now on the clipboard and I can paste them into any other application (, Word, whatever).

Paste the clipboard contents to the shell:

$ pbpaste > foo.txt

Anything that was on the clipboard is now in the file foo.txt.

Using IDEA for Git merging and diffing

A cool bit of CLI trickery that James Humphrey shared with me. This allows you to use IDEA for diffing and merging via git’s mergetool and difftool commands.

First, add IDEA to your path (everything is in Mac-speak here):


export INTELLIJ_HOME /Applications/IntelliJ IDEA


set INTELLIJ_HOME /Applications/IntelliJ IDEA

Next, add these lines to your ~/.gitconfig file:

   tool = intellij
[mergetool "intellij"]
   cmd = idea merge $(cd $(dirname "$LOCAL") && pwd)/$(basename "$LOCAL") $(cd $(dirname "$REMOTE") && pwd)/$(basename "$REMOTE") $(cd $(dirname "$BASE") && pwd)/$(basename "$BASE") $(cd $(dirname "$MERGED") && pwd)/$(basename "$MERGED")
   trustExitCode = true
   tool = intellij
[difftool "intellij"]
   cmd = idea diff $(cd $(dirname "$LOCAL") && pwd)/$(basename "$LOCAL") $(cd $(dirname "$REMOTE") && pwd)/$(basename "$REMOTE")

That’s it. Now you can use IDEA to diff and merge from git CLI like this:

$ git mergetool
$ git difftool

MyBatis TypeHandler phantom errors

I’ve found another annoyance with MyBatis (there are many so be on the lookout for a long blog post that covers everything). This one has to do with how MyBatis handles missing TypeHandlers and required a bit of time stepping through their code.

If you have an object that contains a field whose type is not registered with the TypeHandler registry, MyBatis does not always produce a nice exception for you. Instead, it sometimes decides to return null instead of creating your object.

Here is an example:

 // The domain object
 public class MyDateTimeHolder {
   public DateTime someJodaDateTime;

I’m using Joda’s DateTime object here. If you don’t register this with MyBatis, it can cause this code to fail:

MyDateTimeHolder holder = holderMapper.retrieve();
// holder is null here!!!

The fix is to register the TypeHandler like this:

TransactionFactory transactionFactory = new JdbcTransactionFactory();
Environment environment = new Environment("development", transactionFactory, ds);
Configuration configuration = new Configuration(environment);
configuration.getTypeHandlerRegistry().register(DateTime.class, DateTimeTypeHandler.class);

Order matters with MyBatis Configuration

If you are using MyBatis TypeHandlers in your Configuration, you need to register them BEFORE you add your Mapper instances. As it turns out, MyBatis proactively parses your XML and completely configures each mapper when it is registered. If you mapper XML uses results that need a TypeHandler, you must register those before hand.

Here’s some quick code:

configuration.getTypeHandlerRegistry().register(Locale.class, LocaleTypeHandler.class);

This works because the TypeHandler is registered before the mapper that requires it. This won’t work:

configuration.getTypeHandlerRegistry().register(Locale.class, LocaleTypeHandler.class); // FAIL!

Gradle review

Inversoft has recently switched from Savant to Gradle until Savant 2.0 is finalized and can effectively rolled out (if this ever happens). Gradle is a decent temporary solution, but as a build tool junkie, it rubs me the wrong way. Here are some things that we encountered during the switch that Savant addresses.

Maven Central

We started by attempting to use Maven Central for our dependencies, but quickly realized that Maven Central is a complete mess. We also realized that it suffers from the “most surprise” pattern as well as “GPL” infestation. During our transition, we started to realize that using Maven Central actually caused our number of JARs to dramatically increase and for a couple of GPL JARs to sneak into our classpath.

In the end, we had to rever to managing our own repository and manage all of the ivy.xml dependency files by hand to ensure that everything was correct.

Transitive Mess

Gradle appears to suffer from the “let’s make it simple” methodology of Maven. In order to actually make life simple and avoid actual work, Maven pulls in the entire universe of your project dependencies for compiling and runtime. This means that even if you never import a class from a transitive dependency, Maven puts it in the classpath. This allows you to use classes from transitive dependencies. If you do this though, you’ll never actually know what JAR file a class comes from since it could come from some deeply nested dependency. It also tightly couples your project to your dependencies and those dependencies transitives. We prefer loose coupling rather than tight, so this is generally bad. We also like fewer dependencies at compile time rather than more. Again, bad news all around.

Flat Structure

Gradle plugins and domain are entirely flat. This makes it difficult to separate concerns and distinguish between Java compiling, testing and runtime. Maven actually got this right by cleaning separating concerns and separating plugins.

Configuration vs. tasks

Gradle build files can quickly become large and complex. It is often hard to distinguish between what is configuration and what are tasks.

Order matters

Order matters in Gradle build files unless you always use the String syntax for all configurations and tasks. If you have one task that depends on another task, the order of declaration matters. This is quite painful to debug and I thought we had finally grown out of single pass compiling. Apparently not.

No Versions

There are many pieces of Gradle that don’t like versions, e.g. plugins. These don’t have versions and just use the latest available. This is usually a bad idea because historical builds can break and you’ll never know what version you’ll be using when you execute a build.

MD5 and SHA1?

Why both?

Hashes not always used

The MD5 and SHA1 hashes aren’t always used. For example, the ivy.xml files don’t appear to use the hashes associated with that file. It really should use the hashes for everything.

UploadArchives doesn’t run the tests



Overall, I’m not a big fan of Gradle. It seems to be overly complex and sorta punts on dependency management. Having used Maven, Savant, Ant and Ivy, I would say that Savant 2.0 is still the best build system out there, even though it still isn’t finished.