How I Fixed: Electron builder rcedit-x64.exe”: file does not exist

This is likely a very specific issue to my setup, but on the off chance this helps someone, I figured I would share it.

During Electron builds, whilst building for Windows (NSIS) using GitLab CI on Windows, I kept hitting the following error, causing the build to fail:

   ⨯ cannot execute  cause=exec: "C:\\Windows\\TEMP\\electron-builder-cache\\winCodeSign\\winCodeSign-2.6.0\\rcedit-x64.exe": file does not exist
                     command='C:\Windows\TEMP\electron-builder-cache\winCodeSign\winCodeSign-2.6.0\rcedit-x64.exe' 'C:\gitlab-ci-runner\builds\3RB9ixUo\0\affiliatestatstracker\app\release\win-unpacked\Affiliate Stats Tracker.exe' --set-version-string FileDescription 'Affiliate Stats Tracker' --set-version-string ProductName 'Affiliate Stats Tracker' --set-version-string LegalCopyright 'Copyright © 2020 A6Software' --set-file-version 1.10.0.111 --set-product-version 1.10.0.111 --set-version-string InternalName 'Affiliate Stats Tracker' --set-version-string OriginalFilename '' --set-version-string CompanyName A6Software --set-icon 'C:\gitlab-ci-runner\builds\3RB9ixUo\0\affiliatestatstracker\app\release\.icon-ico\icon.ico'
                     workingDir=
   • Above command failed, retrying 0 more times
 error Command failed with exit code 1.

The fix to this is to ensure the GitLab CI Runner is running as an admin user.

In my case, this means starting Power Shell using “run as administrator”, and then stopping / restarting the GitLab CI Runner.

My issue was caused, it would seem, by running the runner outside of the administrator mode / in regular Power Shell. I don’t use Windows much, sue me.

Anyway, another debug step on this one is to browse to the GitLab CI runner directory, go into the builds directory, right to the dir where GitLab CI left all the files after the previous run failed. From there, you should be able to manually build the project. If you can, likely you have the same issue I had as above.

Like I say, a very specific issue. But hopefully it helps someone, at some point.

How I Fixed: Gatsby GraphQL Cannot query field “query” on type “Query”.

This one had me stumped. And it may be because I’m using GraphQL wrong. But here goes:

I set up a Gatsby site, along with Postgres and Postgraphile to expose GraphQL over my database. This is frankly amazing, and achieves in about 5 minutes what would realistically take weeks to months to code myself.

So far, so good.

In order to get Gatsby to talk to Postgraphile / GraphQL, I needed this bit of config inside gatsby-config.js:

module.exports = {
  plugins: [
    {
      resolve: "gatsby-source-graphql",
      options: {
        // Arbitrary name for the remote schema Query type
        typeName: "segments",
        // Field under which the remote schema will be accessible. You'll use this in your Gatsby query
        fieldName: "segments",
        // Url to query from
        url: "http://0.0.0.0:5000/graphql",
      },
    },
  ],
}

There’s nothing special about this, I just copy / pasted from the docs, and set my typeName and fieldName accordingly.

The typeName and fieldName are important though. And my lack of use are what caused my problem.

Inside my gatsby-node.js file I had a query like:

const result = await graphql(
`
{
segments {
findUniqueCountries {
edges {
node {
country
count
slug
}
}
}
}
}
`
)

This worked fine, and got me back the data I wanted and expected. All good.

Then I moved on, got interrupted, and came back a while later.

I crafted up a new query using the GraphiQL GUI, and had a working result set. All good. Let’s copy / paste that right into the code and carry on, right?

For simplicity, let’s just re-use the query above, but inside GraphiQL:

query MyQuery {
  findUniqueCountries {
    edges {
      node {
        country
        count
        slug
      }
    }
  }
}

That works.

But if you copy / paste it into your code:

 ERROR #85923  GRAPHQL

There was an error in your GraphQL query:

Cannot query field "findUniqueCountries" on type "query".

If you don't expect "findUniqueCountries" to exist on the type "query" it is most likely a typo.
However, if you expect "findUniqueCountries" to exist there are a couple of solutions to common problems:

- If you added a new data source and/or changed something inside gatsby-node.js/gatsby-config.js, please try a restart of your development server
- The field might be accessible in another subfield, please try your query in GraphiQL and use the GraphiQL explorer to see which fields you can query and what shape they have
- You want to optionally use your field "findUniqueCountries" and right now it is not used anywhere. Therefore Gatsby can't infer the type and add it to the GraphQL schema. A quick fix is to add a least one entry with that field ("dummy content")

It is recommended to explicitly type your GraphQL schema if you want to use optional fields. This way you don't have to add the mentioned "dummy content". Visit our docs to learn how you can define the schema for "query":
https://www.gatsbyjs.org/docs/schema-customization/#creating-type-definitions

File: gatsby-node.js:108:24

This confused me no end.

Well, there may be different reasons for why this happens, but in my case it was because in copy / pasting, I was no longer wrapping in the segments type name like in my original working example. Whoops.

Worth a check at your end all the same, as it may be the cause of your problems, too.

Edit: The reason for my confusion, in part, stems from having two GraphiQL instances running. I had one available on port 5000, provided by postgraphile, and another on Gatsby’s default port. If using the GraphiQL provided by Gatsby, there is an extra nested layer (for segments in my case), which does make it easy to copy / paste the query out from the GUI.

How I Fixed: ACF REST API cant_update_item

OK, hopefully this one is as easy to fix for you as it was for me. Easy being the typical (seemingly?) undocumented “one liner” that makes everything work.

In my example, I had just set up WordPress with ACF, added in ACF to REST API, and JWT Authentication for WP-API.

Essentially that gives a combo of admin UI to create and manage the custom fields, and then a REST API endpoint to GET, PUT, POST, etc.

The docs for getting the JWT Authentication plugin set up are good enough. Just a couple of additional define statements required in wp-config.php. Hopefully you have that sorted, and can log in:

curl -X POST \
  https://example.com/wp-json/jwt-auth/v1/token \
  -d '{
	"username": "my_wp_user",
	"password": "my_wp_users_password"
}'

// should return response, e.g. 

{
    "token": "aVeryLongStringHere",
    "user_email": "admin@example.com",
    "user_nicename": "my_wp_user",
    "user_display_name": "Admin Person Name"
}

Sweet. So far, so good.

Next, you need to add in at least one ACF custom field via your admin UI.

I’ve gone with a simple text field.

Even without authenticating, you should be able to hit your WP REST API and see the extra stuff added in by ACF:

curl -X GET \
  https://example.com/wp-json/wp/v2/pages/9

{
  "id": 9,
  "date": "2020-06-17T18:41:01",
  "date_gmt": "2020-06-17T17:41:01",
  "guid": {
  },
  "modified": "2020-06-25T09:13:20",
  "modified_gmt": "2020-06-25T09:15:44",
  "slug": "my-post-slug",
  "status": "publish",
  "type": "page",
  "link": "https://example.com/whatever/something",
  "title": {
  },
  "content": {
  },
  "excerpt": {
  },
  "author": 1,
  "featured_media": 0,
  "parent": 8,
  "menu_order": 0,
  "comment_status": "closed",
  "ping_status": "closed",
  "template": "page-templates/my-page-template.php",
  "meta": [],
  "acf": {
    "example_field": ""
  },
  "_links": {

  }
}

I’ve trimmed this right down. The interesting bit is the acf key / value. Make sure you see it.

The Problem

Things start to get interesting from here on in.

In order to update the post / page / whatever, we will need to be authenticated. We authenticated earlier, and got back a token. We need to pass that token as a Header on any requests that want to add / update data.

This is really easy – just add the header key of Authorization, and the value of Bearer your_token_from_earlier_goes_here. An example follows below.

But more importantly, as best I can tell, we need to use a special endpoint to update ACF fields.

For regular WP data, you might POST or PUT into e.g. https://example.com/wp-json/wp/v2/pages/9 to update data. Technically, PUT is more accurate when updating, and POST is for initial creation, but either seem to work.

curl -X POST \
  https://example.com/wp-json/wp/v2/pages/9 \
  -H 'authorization: Bearer aVeryLongStringHere' \
  -d '{
    "slug": "my-updated-slug"
}'

// which should return a full JSON response with the all the data, and the updated slug.

But if you try to update ACF this way, it just silently ignores your change:

curl -X POST \
  https://example.com/wp-json/wp/v2/pages/9 \
  -H 'authorization: Bearer aVeryLongStringHere' \
  -d '{
	"acf": {
	    "example_field": "some interesting update"
	}
}'

// it should 'work' - you get a 200 status code, and a full JSON response, but 'example_field' will not have updated.

My intuition says that seeing as we followed the response structure, this should have worked. But clearly, it doesn’t.

But it turns out that we need to use a separate endpoint for ACF REST API updates:

curl -X GET \
  https://example.com/wp-json/wp/v2/pages/9

// note again, no auth needed for this GET request

{
	"acf": {
	    "example_field": ""
	}
}

So this works, too. This only returns the acf field subset. But still, confusingly, the top level key is acf. And that’s what threw me.

See, if we try to make a POST or PUT following this shape:

curl -X POST \
  https://example.com/wp-json/wp/v2/pages/9 \
  -H 'authorization: Bearer aVeryLongStringHere' \
  -d '{
	"acf": {
	    "example_field": "some interesting update"
	}
}'

// fails, 500 error

{
    "code": "cant_update_item",
    "message": "Cannot update item",
    "data": {
        "status": 500
    }
}

And the same goes for if we drop the acf top level key:

curl -X POST \
  https://example.com/wp-json/wp/v2/pages/9 \
  -H 'authorization: Bearer aVeryLongStringHere' \
  -d '{ example_field": "some interesting update" }'

// fails, 500 error

{
    "code": "cant_update_item",
    "message": "Cannot update item",
    "data": {
        "status": 500
    }
}

The Solution

As I said at the start, this is a one liner. And as far as I could see, it’s not *clearly* documented. Maybe it’s in there somewhere. Maybe if you use WP day in, day out, you already know this. I don’t. And so I didn’t.

Hopefully this saves you some time:

curl -X POST \
  https://example.com/wp-json/wp/v2/pages/9 \
  -H 'authorization: Bearer aVeryLongStringHere' \
  -d '{
	"fields": {
            "example_field": "some interesting update"
      }
}'

// works, 200, response:

{
	"acf": {
	    "example_field": "some interesting update"
	}
}

And lo-and-behold, that works.

I think it’s super confusing that the field key is used on create / update, but the acf key is returned on read. Admittedly I have done this myself on API’s before – but as a consumer I now realise how unintuitive and frustrating that is.

How I Fixed: docker: invalid reference format With Makefile

I’m a big fan of makeshift Makefiles. Largely because I don’t seem to have the brain capacity to remember long winded commands. Or maybe, I just don’t like typing out long winded commands. One of the two reasons, for sure.

In using a Makefile to set up a local DNS server to help resolve an issue with multiple different related, but separated Docker projects being able to talk to one another, I ended up coming across this Stack Overflow post which was very helpful.

The solution from the post calls for running a Docker command to spin up a local DNS server, which then allows all the disparate services to talk to one another via hostname, rather than IP address.

I dutifully created a new Makefile entry:

start_dev_dns:
	@docker run \
		--rm \ 
		--hostname=dns.mageddo \
		-p 5380:5380 \
		-v /var/run/docker.sock:/var/run/docker.sock \
		-v /etc/resolv.conf:/etc/resolv.conf \
		defreitas/dns-proxy-server

It’s hard to spot the fault here. That command looks right to me.

I copy / pasted the command direct from the Stack Overflow post, added in the --rm flag to ensure the resulting container gets removed when I kill it, and then tried to run the command:

 ➜ myproject.whatever make start_dev_dns
docker: invalid reference format.
See 'docker run --help'.
make: *** [Makefile:8: start_dev_dns] Error 125

Boo.

Anyway, after a bit of head scratching, it turns out the issue was an extra space after the line continuation slash.

Really hard to display this one on a blog post. But essentially if you see this and you’re in a similar situation, check you don’t have any rogue spaces after the \‘s at the end of each line.

How To Get Variables From package.json In Your JS / TS Code

Let’s say you have a bit of information inside package.json that you’d like to use somewhere in your code. An example of this in my case is the version string which I have to set for Electron to then generate the new file name for the “built” version of my app.

I figured if I’m specifying the version in package.json, I could display that value in the app footer. This would then, hopefully, help with a variety of first step debugging processes / help / support requests. It’s a quick visual check to ensure the user is on the latest version.

Anyway, this is one of them things that doesn’t come up for me that often, and when it does, I tend to forget how to do it.

import { version as appVersion } from '../package.json';

const Footer = () => {
  return (
    <footer>
      <p>
        v{appVersion} © 2019 -{' '}
        {new Date().getFullYear()} A6 Software Ltd. All rights reserved.
      </p>
    </footer>
  );
};

(Ugh, seems WordPress code formatting has some … issues, shall we say, at present)

Pretty straightforward.

package.json is not a special case here, even though it might seem like it would be. This is how you can get a value from any JSON file.

This may not work immediately, it really depends on how your project is set up.