java.lang.IllegalArgumentException: path may not be null or empty string. path='null'

Aargh.

This exception has now bitten me. I haven’t the slightest idea what to make of it.
It occurs when trying to execute a plugin that I wrote, an extension of nebula’s rpm plugin. I have written at least 100 build scripts using these plugins and never seen an error like this.

Not a single line of the stack trace comes from my plugin or build script code.

java.lang.IllegalArgumentException: path may not be null or empty string. path='null'
        at org.gradle.api.internal.file.AbstractBaseDirFileResolver.doResolve(AbstractBaseDirFileResolver.java:65)
        at org.gradle.api.internal.file.AbstractFileResolver.resolve(AbstractFileResolver.java:86)
        at org.gradle.api.internal.file.AbstractFileResolver.resolve(AbstractFileResolver.java:68)
        at org.gradle.api.internal.file.collections.DefaultFileCollectionResolveContext$FileTreeConverter.convertInto(DefaultFileCollectionResolveContext.java:215)
        at org.gradle.api.internal.file.collections.DefaultFileCollectionResolveContext.doResolve(DefaultFileCollectionResolveContext.java:138)
        at org.gradle.api.internal.file.collections.DefaultFileCollectionResolveContext.resolveAsFileTrees(DefaultFileCollectionResolveContext.java:87)
        at org.gradle.api.internal.file.collections.DefaultFileCollectionResolveContext$FileTreeConverter.convertInto(DefaultFileCollectionResolveContext.java:192)
        at org.gradle.api.internal.file.collections.DefaultFileCollectionResolveContext.doResolve(DefaultFileCollectionResolveContext.java:111)
        at org.gradle.api.internal.file.collections.DefaultFileCollectionResolveContext.resolveAsFileTrees(DefaultFileCollectionResolveContext.java:87)
        at org.gradle.api.internal.file.CompositeFileCollection$1.visitContents(CompositeFileCollection.java:111)
        at org.gradle.api.internal.file.CompositeFileTree$FilteredFileTree.visitContents(CompositeFileTree.java:114)
        at org.gradle.api.internal.file.collections.DefaultFileCollectionResolveContext.resolveNested(DefaultFileCollectionResolveContext.java:147)
        at org.gradle.api.internal.file.collections.DefaultFileCollectionResolveContext.doResolve(DefaultFileCollectionResolveContext.java:114)
        at org.gradle.api.internal.file.collections.DefaultFileCollectionResolveContext.resolveAsFileCollections(DefaultFileCollectionResolveContext.java:94)
        at org.gradle.api.internal.file.collections.DefaultFileCollectionResolveContext$FileCollectionConverter.convertInto(DefaultFileCollectionResolveContext.java:161)
        at org.gradle.api.internal.file.collections.DefaultFileCollectionResolveContext.doResolve(DefaultFileCollectionResolveContext.java:111)
        at org.gradle.api.internal.file.collections.DefaultFileCollectionResolveContext.resolveAsFileCollections(DefaultFileCollectionResolveContext.java:94)
        at org.gradle.api.internal.file.CompositeFileCollection.getSourceCollections(CompositeFileCollection.java:172)
        at org.gradle.api.internal.file.CompositeFileCollection.isEmpty(CompositeFileCollection.java:79)
        at org.gradle.api.internal.tasks.execution.SkipEmptySourceFilesTaskExecuter.execute(SkipEmptySourceFilesTaskExecuter.java:50)
        at org.gradle.api.internal.tasks.execution.ResolveTaskArtifactStateTaskExecuter.execute(ResolveTaskArtifactStateTaskExecuter.java:52)
        at org.gradle.api.internal.tasks.execution.SkipTaskWithNoActionsExecuter.execute(SkipTaskWithNoActionsExecuter.java:52)
        at org.gradle.api.internal.tasks.execution.SkipOnlyIfTaskExecuter.execute(SkipOnlyIfTaskExecuter.java:54)
        at org.gradle.api.internal.tasks.execution.ExecuteAtMostOnceTaskExecuter.execute(ExecuteAtMostOnceTaskExecuter.java:43)
        at org.gradle.api.internal.tasks.execution.CatchExceptionTaskExecuter.execute(CatchExceptionTaskExecuter.java:34)
        at org.gradle.execution.taskgraph.DefaultTaskGraphExecuter$EventFiringTaskWorker$1.run(DefaultTaskGraphExecuter.java:248)
        at org.gradle.internal.progress.DefaultBuildOperationExecutor$RunnableBuildOperationWorker.execute(DefaultBuildOperationExecutor.java:336)
        at org.gradle.internal.progress.DefaultBuildOperationExecutor$RunnableBuildOperationWorker.execute(DefaultBuildOperationExecutor.java:328)
        at org.gradle.internal.progress.DefaultBuildOperationExecutor.execute(DefaultBuildOperationExecutor.java:197)
        at org.gradle.internal.progress.DefaultBuildOperationExecutor.run(DefaultBuildOperationExecutor.java:107)
        at org.gradle.execution.taskgraph.DefaultTaskGraphExecuter$EventFiringTaskWorker.execute(DefaultTaskGraphExecuter.java:241)
        at org.gradle.execution.taskgraph.DefaultTaskGraphExecuter$EventFiringTaskWorker.execute(DefaultTaskGraphExecuter.java:230)
        at org.gradle.execution.taskgraph.DefaultTaskPlanExecutor$TaskExecutorWorker.processTask(DefaultTaskPlanExecutor.java:124)
        at org.gradle.execution.taskgraph.DefaultTaskPlanExecutor$TaskExecutorWorker.access$200(DefaultTaskPlanExecutor.java:80)
        at org.gradle.execution.taskgraph.DefaultTaskPlanExecutor$TaskExecutorWorker$1.execute(DefaultTaskPlanExecutor.java:105)
        at org.gradle.execution.taskgraph.DefaultTaskPlanExecutor$TaskExecutorWorker$1.execute(DefaultTaskPlanExecutor.java:99)
        at org.gradle.execution.taskgraph.DefaultTaskExecutionPlan.execute(DefaultTaskExecutionPlan.java:625)
        at org.gradle.execution.taskgraph.DefaultTaskExecutionPlan.executeWithTask(DefaultTaskExecutionPlan.java:580)
        at org.gradle.execution.taskgraph.DefaultTaskPlanExecutor$TaskExecutorWorker.run(DefaultTaskPlanExecutor.java:99)
        at org.gradle.internal.concurrent.ExecutorPolicy$CatchAndRecordFailures.onExecute(ExecutorPolicy.java:63)
        at org.gradle.internal.concurrent.ManagedExecutorImpl$1.run(ManagedExecutorImpl.java:46)
        at org.gradle.internal.concurrent.ThreadFactoryImpl$ManagedThreadRunnable.run(ThreadFactoryImpl.java:55)

The only clue I have is one line of the above stack trace:
at org.gradle.api.internal.tasks.execution.CatchExceptionTaskExecuter.execute(CatchExceptionTaskExecuter.java:34)

This sounds like something may have thrown an exception, which gradle then ate and dove into a path that completely obscured what the original problem was. What is the CatchExceptionTaskExecuter?

This happens with Gradle 4.1.

Please help!

I’ve figured out what the null is. This particular variety of rpm plugin is trying something no earlier one has. It doesn’t know the “from” for one of its copyspecs until a separate configuration task has run. Nonetheless I want this file to go into the rpm I’m building. Even though I’ve specified a getter() as the from, this is still getting called at configure time when it is still null. I’ve tried every lazy evaluation trick I know to delay evaluation, and it doesn’t work.

How may I generate a copy spec at dynamically at runtime?

I’ve used configuration tasks in the past with copyspec-like tasks. Can you provide a working example that demonstrates the issue you’re seeing?

Something like this should work:

task configureCopy {
    doLast {
        tasks.myCopy.from( 'xyz' )
    }
}

task myCopy( type: Copy ) {
    dependsOn tasks.configureCopy

    into( 'somewhere' )
}